Spring
阅读提示
Spring 面试常见追问链路:IOC -> AOP -> 事务 -> 循环依赖。
建议先记住每个主题的结论句,再补关键机制细节。
适用范围:以 Spring Framework 6.2、Spring Boot 3.5 的 Servlet 应用为基线。事务默认指代理模式下的命令式事务;响应式事务使用 Reactor 上下文,不能直接套用线程绑定的解释。历史差异在对应位置说明。
1、SpringBean的作用域
参考回答:
- singleton:默认作用域,同一容器内同一Bean定义对应一个实例,并非整个JVM唯一。适合无状态服务;共享可变状态仍需同步。
- prototype:每次向容器获取或解析依赖时创建实例。注入单例Bean时通常只解析一次,后续仍复用该实例;需要每次使用新实例时可注入
ObjectProvider<T>并调用getObject()。 - request:每个HTTP请求一个实例,仅适用于Web感知的ApplicationContext。
- session:每个HTTP Session一个实例,用于保存会话状态。
- application:同一ServletContext共享一个实例,与每容器、每定义的singleton范围不同。
- websocket:同一WebSocket会话共享一个实例,用于Spring WebSocket的会话作用域。
旧Portlet环境的globalSession不属于Spring 6.2内置作用域。作用域控制对象创建与复用,不自动提供线程安全。参见官方Bean作用域。
2、SpringBean的生命周期
参考回答:
- 实例化:ApplicationContext通常在刷新时预实例化非懒加载单例,懒加载Bean按需创建。实例可通过构造器、工厂方法等创建;
BeanFactoryPostProcessor在普通Bean实例化前修改Bean定义,不是逐个Bean的实例化回调。 - 属性赋值:Spring IoC容器在创建Bean的过程中,会将Bean在XML文件中配置的属性值和
BeanDefinition中的属性值设置到Bean中。这里主要指Setter/字段注入;构造器依赖在实例化时解析并传入。 - Bean后处理器(BeanPostProcessor)处理:在Bean的实例化和属性赋值之后,Spring会调用
BeanPostProcessor的postProcessBeforeInitialization方法,对Bean进行进一步的处理。这是一个可选的步骤,开发者可以通过实现BeanPostProcessor接口并覆盖相应的方法来定义自己的处理逻辑。 - 初始化:如果Bean在容器中配置了
init-method,那么这个方法将会被调用,完成Bean的初始化操作。多个不同初始化回调共存时,顺序为@PostConstruct、InitializingBean.afterPropertiesSet()、自定义init-method。其中@PostConstruct由初始化前的后处理器触发。这也是一个可选的步骤,但通常用于在Bean的所有属性设置完毕后执行一些初始化操作。 - 实例化后处理:在Bean完成初始化之后,Spring会再次调用
BeanPostProcessor的postProcessAfterInitialization方法,对Bean进行最后的处理。这也是一个可选的步骤,开发者可以在这里添加一些额外的逻辑,例如对Bean进行代理等。 - 使用:此时Bean已经准备就绪,可以被应用程序使用了。Spring容器会管理Bean的生命周期,并在需要的时候将其提供给应用程序。
- 销毁:当Spring容器关闭时,它会调用所有实现了
DisposableBean接口的Bean的destroy方法,并触发在XML配置文件中定义的destroy-method。多个不同销毁回调的顺序为@PreDestroy、destroy()、自定义销毁方法。prototype的销毁回调不由容器自动管理,资源需由调用方释放。参见官方生命周期回调。
3、Spring AOP原理
参考回答:
Spring AOP(Aspect Oriented Programming,面向切面编程)的原理主要基于动态代理模式,用于在不修改原有业务代码的前提下,为多个目标对象统一管理并增加额外功能。其核心概念包括切面(Aspect)、连接点(Join Point)、通知(Advice)等。
切面(Aspect):切面封装横切关注点,由切点和通知等组成;切点负责筛选需要增强的连接点。切面可以包括前置通知、后置通知、环绕通知、异常通知和最终通知等,具体可以根据业务需求自定义实现。
连接点(Join Point):连接点表示切面将会被织入到目标对象的哪个位置,Spring AOP仅支持方法执行连接点;构造器和字段访问等属于完整AspectJ的能力范围。
通知(Advice):通知包括各种类型的切面代码,如前置通知、后置通知、环绕通知、异常通知和最终通知等。这些通知会在连接点执行时被触发。
Spring AOP以动态代理技术为主要方式进行织入。具体来说,当目标对象的方法被调用时,Spring AOP会检查该方法是否是一个连接点。如果是,则会在方法执行前后(或者方法执行过程中)织入相应的通知代码。这些通知代码可以在不修改原有业务代码的情况下,为目标对象增加额外的功能。
Spring AOP使用JDK接口代理或CGLIB子类代理。private方法以及CGLIB不能覆盖的final方法无法被增强;this.method()自调用不经过代理,也不会触发该方法的通知。参见官方代理机制。
4、Spring事务传播机制
参考回答:
REQUIRED(默认):
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说,无论外部方法是否开启事务,
REQUIRES_NEW修饰的内部方法都会新开启自己的事务,内层提交不会随外层回滚而撤销;但内层异常继续向外抛出时,仍可能触发外层回滚。内层通常还需要额外连接,应考虑连接池容量。NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。
NESTED:
存在事务时使用同一物理事务中的保存点:内层可回滚到保存点,外层仍可继续;外层最终回滚会撤销全部修改,内层不能独立提交。不存在事务时按REQUIRED开启事务。需要事务管理器和底层资源支持,典型是支持JDBC保存点的DataSourceTransactionManager,不能假定所有JPA/JTA场景都支持。
REQUIRED的多个逻辑事务共享物理事务:内层标记rollback-only后,即使外层捕获异常,最终提交仍可能抛出UnexpectedRollbackException。这些传播语义以调用经过事务拦截器为前提。参见官方事务传播。
5、什么是Spring的循环依赖问题?(了解)
参考回答:
- Spring的循环依赖问题是指在Spring容器中,两个或多个Bean之间相互依赖,形成了一个循环引用的情况。具体来说,当一个Bean A依赖于另一个Bean B,而Bean B又依赖于Bean A时,就可能出现循环依赖的问题。
6、什么是spring三级缓存以及如何解决循环依赖(重要)
参考回答:
- 一级缓存(singletonObjects):保存完成创建流程、可正常使用的单例对象,可能是代理。
- 二级缓存(earlySingletonObjects):保存已经取得的早期引用,可能是原对象或早期代理,其依赖尚未全部注入。
- 三级缓存(singletonFactories):保存获取早期引用的
ObjectFactory,不是重新实例化Bean的工厂。单例实例化后、属性填充前注册工厂;真正需要早期引用时,通过getEarlyBeanReference取得引用并缓存到二级缓存。完成创建后放入一级缓存,清理早期条目。
实例化A → 注册A的早期引用工厂 → 为A注入B
→ 实例化B → B需要A → 调用A的工厂,缓存并注入A的早期引用
→ 完成B → 完成A → 将最终单例放入一级缓存三级工厂将早期代理的生成推迟到真正需要时,二级缓存复用同一早期引用,有助于保持依赖方引用一致。它管理Bean对象,与减少数据库访问无关。该机制主要处理允许循环引用时的单例Setter/字段依赖;纯构造器循环在实例化前就互相等待,prototype循环也不能靠它解决,部分代理组合仍可能失败。
Spring Boot自2.6起默认禁止循环引用,3.5同样如此。spring.main.allow-circular-references=true只允许容器尝试解决,并不保证成功;优先拆开双向依赖。参见官方Boot 2.6发布说明和Spring 6.2.0 Bean创建源码的doCreateBean、getEarlyBeanReference。
6、spring事务失效的原因?
参考回答:
- 方法不满足代理条件:正确注解名是
@Transactional。JDK代理要求public接口方法;自Spring 6.0起,类代理默认也支持protected及包可见方法。private方法不能被代理增强,CGLIB也无法增强final方法,不能笼统说非public全部失效。 - 类没有被Spring管理:Spring事务是由AOP机制实现的,AOP机制的本质就是动态代理。从Spring IOC容器获取bean时,Spring会为目标类创建代理,从而支持事务。如果类没有被Spring容器管理(例如,没有添加@Service、@Component等注解),则Spring无法为目标类创建代理,事务也会失效。
- 异常被捕获且未正确处理:默认情况下,Spring只有在方法抛出运行时异常或者错误时才会回滚事务。异常在方法内被捕获且未再抛出时,拦截器通常看不到失败;受检异常默认也不触发回滚,可配置rollbackFor。但事务若已被参与方标记rollback-only,捕获异常也不能恢复提交。
- 事务属性设置不当:如果在Spring的事务管理中,事务的传播特性(propagation)或回滚规则(rollbackFor)设置不当,也可能导致事务失效。例如,如果在一个支持当前事务的方法中调用了需要新事务的方法,并且后者方法抛出了异常,但异常并未被Spring识别为需要回滚事务的异常,那么后者的事务将不会回滚。
- 数据库配置问题:如果数据库配置不支持事务(例如,使用了不支持事务的数据库引擎),或者数据库本身就是不支持事务的,那么Spring事务也会失效。
- 调用同一个类中的方法:默认代理模式下,即使内部方法标了
@Transactional,this自调用仍绕过代理,内部方法的新传播/隔离设置不会被拦截。外部入口已有事务时,内部数据库操作仍可能参与该事务,不代表原事务消失。这是因为Spring是通过代理模式来管理事务的,只有在代理对象上调用方法时,事务才会生效。 - 事务嵌套使用不当:在一个已经开启了事务的方法中再次开启事务,对于Spring的PROPAGATION_REQUIRED模式(默认模式),它只会用原来的事务,这可能导致预期之外的行为。
7、spring bean是否为线程安全的?
参考回答:
Spring容器不自动为Bean添加线程安全保护。singleton可能被多线程共享,但无状态或正确同步的Bean可以线程安全;prototype只控制创建频率,被注入单例后复用或被主动共享时仍可能并发访问,不能仅凭作用域判断。
8、spring中用到的设计模式?
参考回答:
工厂模式(Factory Pattern):
Spring使用工厂模式通过
BeanFactory、ApplicationContext等接口创建并管理对象实例。这种方式将对象的创建与使用解耦,使得程序更加灵活和可扩展。单例模式(Singleton Pattern):
Spring中的Bean默认都是单例的,即在整个Spring IoC容器中,每个Bean只会有一个实例。这通过Bean的scope属性进行控制,当scope为singleton时,即表示使用单例模式。
代理模式(Proxy Pattern):
在AOP(面向切面编程)和remoting中被广泛使用。Spring AOP的实现基于动态代理模式,可以在运行时动态地将代码切入到类的指定方法、指定位置上。
模板方法模式(Template Method Pattern):
解决代码重复问题。Spring中例如
JdbcTemplate就是模板方法模式的体现,它封装了数据访问的底层操作,定义了数据访问的骨架,使得开发者可以只关注自己的业务SQL。前端控制器模式(Front Controller Pattern):
Spring MVC中的
DispatcherServlet就是前端控制器模式的实现,它负责接收请求,并根据请求信息调用相应的处理器(Controller)进行处理。依赖注入模式(Dependency Injection Pattern):
贯穿于
BeanFactory和ApplicationContext接口的核心理念。通过依赖注入,Spring可以在运行时动态地将一个对象所需要的外部依赖注入到该对象中,从而降低了代码的耦合度。装饰器模式(Decorator Pattern):
在Spring中,
BeanWrapper是一个很好的装饰器模式的例子。它允许你在运行时动态地给一个对象添加一些额外的职责。委派模式(Delegation Pattern):
在Spring MVC中,
DispatcherServlet就是一个典型的委派模式的例子。它接收请求,但并不处理请求,而是将请求委派给相应的控制器进行处理。策略模式(Strategy Pattern):
在Spring中,
HandlerMapping接口的实现类就使用了策略模式。它定义了一个处理请求的接口,具体的处理策略由实现类来完成。适配器模式(Adapter Pattern):
在Spring MVC中,
HandlerAdapter接口的实现类就使用了适配器模式。它将不同的处理器(Controller)适配成统一的接口,使得DispatcherServlet可以统一调用。观察者模式(Observer Pattern):
在Spring的事件驱动模型中,使用了观察者模式。当某个事件发生时,会通知所有注册的观察者(Listener)进行处理。
能说一部分就行了
9、Spring IOC
参考回答:
Spring IoC(Inversion of Control,控制反转)是Spring框架的核心特性之一。它的基本思想是将对象的创建和管理过程从应用程序代码中抽离出来,由Spring容器负责创建和管理对象之间的依赖关系。通过这种方式,应用程序代码不再需要直接创建和管理对象,而是向Spring容器发出请求,由容器负责创建和返回所需的对象。
Spring IoC的主要优点包括:
降低耦合性:通过IoC容器来管理对象之间的依赖关系,使得系统更加模块化、可测试和易于扩展。
提高灵活性和可维护性:由于对象的创建和管理由Spring容器负责,因此可以更加灵活地配置和修改对象的行为。同时,由于代码不再包含对象的创建和管理逻辑,因此可以更加专注于业务逻辑的实现,提高代码的可维护性。
支持多种配置方式:Spring IoC支持多种配置方式,包括XML配置、注解配置和Java配置等。这些配置方式可以根据项目的实际需求进行灵活选择和使用。
在实现Spring IoC时,有三种主要的方式:
使用XML实现Spring IoC:通过编写XML配置文件来定义和配置Bean,将配置信息集中在一个XML文件中进行管理。
使用注解方式实现Spring IoC:通过在类和方法上添加注解来定义和配置Bean,使得配置更加简洁、直观,并且减少了对XML文件的依赖。
使用JavaConfig实现Spring IoC:通过编写Java配置类来定义和配置Bean,将配置信息集中在一个Java类中,提供了一种更加面向对象和类型安全的配置方式。
10、spring AOP在项目中的应用场景?
参考回答:
- 日志记录:在系统中记录日志是非常重要的,可以使用AOP来实现日志记录的功能。通过在方法执行前、执行后或异常抛出时记录日志,可以方便地跟踪系统的运行情况和问题排查。
- 事务管理:在数据库操作或其他需要事务管理的操作中,使用AOP可以将事务管理的逻辑与业务逻辑分离,使得事务的控制更加简单和集中。通过AOP,可以在方法开始前开启事务,在方法执行完毕后提交或回滚事务,以确保数据的一致性和完整性。
- 安全控制:在系统中包含某些需要安全控制的操作,如登录、修改密码、授权等,可以使用AOP来实现安全控制的功能。通过AOP,可以在方法调用前进行安全性检查,例如检查用户的权限或身份验证,以确保只有授权用户可以访问特定的方法或资源。
- 性能监控:在系统运行过程中,有时需要对某些方法的性能进行监控,以找到系统的瓶颈并进行优化。通过AOP,可以在方法调用前后记录方法的执行时间,以监控和优化系统的性能。
- 缓存控制:在系统中有些数据可以缓存起来以提高访问速度,可以使用AOP来实现缓存控制的功能。通过AOP,可以在方法执行前查询缓存中是否有数据,如果有则返回,否则执行方法并将方法返回值存入缓存中。
- 异常处理:使用AOP,可以集中处理方法中抛出的异常,例如将异常转换为统一的错误码或进行日志记录。这有助于更好地管理和监控异常,并降低异常对系统的影响。
- 参数校验和转换:使用AOP,可以在方法调用前对方法的参数进行校验和转换,以确保参数的有效性和符合业务要求。这有助于减少因参数问题导致的错误和异常,并提高系统的健壮性。
12、Spring中如何开启事务?
参考回答:
编程式事务:
编程式事务是通过编程的方式自己去实现事务,可以使用
TransactionTemplate.execute(...)划定事务边界,由模板处理提交与回滚;也可直接使用PlatformTransactionManager,但需自行处理异常和资源清理。这种事务管理方式需要在逻辑代码中手动书写事务控制逻辑,因此是侵入性的。它的缺点是代码复用性差,每一个事务都需要自己编写事务逻辑,可能会造成代码冗余。然而,它的优点在于事务边界更容易控制,可以在业务的任意位置进行事务提交或者回滚操作。
声明式事务:
声明式事务则是通过配置或注解的方式,将事务管理逻辑与业务逻辑进行分离,由Spring框架来自动处理事务的开启、提交和回滚。
使用声明式事务时,通常会在业务层(service层)的方法上、类上或接口上使用
@Transactional注解。当方法执行前,Spring会自动开启事务;如果方法成功执行完毕,Spring会提交事务;如果异常匹配回滚规则,Spring会回滚事务;默认是RuntimeException和Error,受检异常默认不回滚。普通Spring配置需通过
@EnableTransactionManagement或XML启用事务管理,并配置合适的事务管理器。Spring Boot满足自动配置条件时可自动启用,无需重复添加注解。参见官方事务注解与代理边界。
13、Spring ioc在项目中的应用场景?(了解)
参考回答:
解耦与模块化:
在复杂的系统中,各个组件之间可能存在复杂的依赖关系。使用Spring IoC,可以将这些依赖关系交由Spring容器管理,使得组件之间的耦合度降低,提高了系统的模块化程度。
依赖注入:
Spring IoC支持依赖注入(Dependency Injection, DI),这意味着Spring容器会自动将所需的依赖项注入到对象的实例中。这使得开发者无需在代码中手动创建和管理依赖对象,从而简化了代码并提高了可读性。
配置集中管理:
Spring IoC允许开发者将配置信息(如数据库连接信息、第三方服务接口地址等)集中在一个或多个配置文件中(如XML文件、Java配置类或YAML文件)。这样,当配置信息需要变更时,只需修改配置文件而无需修改代码。
插件化开发:
在一些大型系统中,可能需要支持多种插件或扩展。通过使用Spring IoC,可以将这些插件或扩展作为独立的组件进行开发,并通过配置文件或注解将它们集成到系统中。这使得插件的添加、删除和替换变得更加容易。
测试支持:
在测试过程中,可能需要模拟或替换某些组件的依赖项。Spring IoC提供了方便的测试支持,允许开发者在测试环境中注入模拟对象或测试数据,从而验证系统的正确性。
动态代理:
Spring IoC结合AOP(Aspect-Oriented Programming,面向切面编程)可以实现动态代理。动态代理允许开发者在不修改原始代码的情况下,为类添加额外的功能(如日志记录、事务管理、性能监控等)。这使得系统的功能扩展变得更加灵活和方便。
容器化应用:
在云原生和微服务架构中,应用通常以容器的形式部署。Spring IoC作为Spring框架的核心特性之一,可以与容器化技术(如Docker、Kubernetes等)很好地结合使用。通过Spring IoC管理应用的依赖关系,可以确保应用在容器化环境中能够正常运行并与其他服务进行交互。
14、SpringBoot和Spring的区别是什么?(了解)
参考回答:
- 设计理念:Spring是一个全面的框架,它提供了许多功能,但同时也增加了项目的复杂度。相反,Spring Boot旨在简化Spring应用程序的初始搭建和开发过程,尽可能自动配置Spring应用程序。基于“约定优于配置”的原则,Spring Boot简化了项目的配置流程。
- 创建独立应用:Spring Boot可以创建独立的Spring应用程序。它集成了Tomcat、Jetty和Undertow等服务器,并且不需要部署它们。这意味着开发者可以直接打包他们的应用程序为一个可执行的JAR或WAR文件,从而简化了部署过程。
- 配置:在Spring中,我们需要进行大量的XML配置、JavaConfig和注解处理,以整合各种组件。而在Spring Boot中,它使用了特定的方式来进行配置,极大地简化了这些文件的配置过程。例如,Spring Boot引入了“starters”的概念,这些是预先配置好的Maven依赖项,可以简化Maven配置。
- 嵌入式容器:Spring Boot嵌入了一个Web服务器(如Tomcat、Jetty或Undertow),这使得应用程序可以作为一个独立的可执行JAR或WAR文件运行,而不需要单独的服务器或容器。
- 自动配置:Spring Boot的强大之处在于其自动配置功能。它通过检查项目的类路径、属性设置和其他条件,自动为你配置Spring应用程序。例如,如果你在类路径中添加了H2数据库,Spring Boot会自动为你配置一个内存数据库。
- 依赖管理:在Spring Boot中,你只需要引入相应的starter依赖,就可以快速地整合第三方库和框架。这种依赖管理方式使得项目结构更加清晰,减少了版本冲突的可能性。
15、springBean的初始化过程?
参考回答:
- Bean的定义:
- 在Spring配置中定义Bean的信息,包括类名、属性、作用域等。
- Bean的加载和解析:
- Spring容器启动时,加载并解析配置文件或注解,生成
BeanDefinition对象。
- 实例化Bean:
- 根据
BeanDefinition通过构造器或工厂方法创建实例;正常单例在初始化完成后进入一级缓存,循环依赖时可能先暴露早期引用。
- 依赖注入:
- 为Bean注入所需的依赖,方式包括构造器注入、setter方法注入和字段注入。
- 初始化前处理:
- 如果存在
BeanPostProcessor,调用其postProcessBeforeInitialization方法,对Bean进行初始化前的定制化处理。
- 调用初始化方法:
执行Bean的初始化方法,可能包括:
使用
@PostConstruct注解的方法(由初始化前的后处理器触发)。实现
InitializingBean接口的afterPropertiesSet方法。在配置中指定的
init-method方法。
以上为不同回调共存时的顺序;Spring 6使用jakarta.annotation.PostConstruct。
- 初始化后处理:
- 如果存在
BeanPostProcessor,调用其postProcessAfterInitialization方法,对Bean进行初始化后的定制化处理,如AOP代理等。
- Bean的就绪和使用:
- 经过上述步骤,Bean已完全初始化,可以通过
getBean()方法获取并使用。
16、如何在Spring启动过程中做缓存预热?
参考回答:
- 监听应用启动事件:Spring Boot提供了多种方式来监听应用启动事件,以便在应用启动后执行特定的逻辑。你可以使用
@EventListener注解或实现ApplicationListener接口来监听ApplicationReadyEvent事件。当这个事件被触发时,位于Runner执行完成之后,随后发布接受流量的就绪状态;不代表Web端口此时才开始监听。 - 使用CommandLineRunner或ApplicationRunner:如果你不想直接监听
ApplicationReadyEvent事件,你也可以使用CommandLineRunner或ApplicationRunner接口。这两个接口都定义了一个run方法,Spring Boot会在所有Spring Beans都初始化完成之后调用这个方法。 - 使用@PostConstruct注解:使用 @PostConstruct 注解标注一个方法,该方法在Bean依赖注入完成后、常规初始化回调期间执行,并非构造后立即执行。适合本Bean的轻量初始化;启动必需的跨Bean预热可放到Boot的Runner中,避免依赖尚未完成的代理。参见官方启动事件与Runner。
17、spring中常用注解?
参考回答:
组件注解:
@Component:用于标识一个类为Spring的组件,可以被自动扫描并注册为Bean。@Controller:用于标识一个类为控制器层(Controller)组件,通常用于处理HTTP请求。@Service:用于标注业务逻辑层组件,即Service层。@Repository:用于标识一个类为数据访问层(DAO)组件,用于操作数据库。@RestController:结合@Controller和@ResponseBody,用于标识一个类为RESTful风格的控制器,用于返回JSON或XML数据。注入注解:
@Autowired:由Spring提供,用于自动注入依赖。它默认按类型匹配的方式在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入到标注的变量中。@Qualifier:与@Autowired配合使用,用于在存在多个相同类型的Bean时,指定要注入的Bean的名称或限定符。@Resource:与@Autowired类似,但除了按类型匹配外,还支持按名称匹配。@Value:用于注入配置文件中的值或表达式的结果,例如注入一个字符串或数字常量。Java配置类相关注解:
@Configuration:用于标识一个类为配置类,通常与@Bean一起使用,以替代传统的XML配置文件。@Bean:注解在方法上,声明当前方法的返回值为一个Bean,用于在配置类中定义Bean。切面(AOP)相关注解:
@Aspect:声明一个切面,用于定义通知(Advice)和切点(Pointcut)。@Before、@After、@AfterReturning、@AfterThrowing、@Around:这些注解用于定义通知,分别表示在方法执行前、后、返回后、抛出异常后和环绕方法执行通知。其他常用注解:
@RequestMapping:用于映射Web请求到特定的处理器方法。@PathVariable:用于从URI模板变量中解析值,并绑定到方法参数上。@RequestParam:用于从请求参数中解析值,并绑定到方法参数上。@RequestBody:用于将HTTP请求正文转换为Java对象。@ResponseBody:用于将Java对象转换为HTTP响应正文。
18、spring中注入方式?
参考回答:
- set()方法注入;
- 构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
- 字段注入:使用
@Autowired等,但依赖不如构造器显式。
静态工厂与实例工厂是Bean创建方式,工厂方法参数也可由容器注入,不宜与构造器/Setter注入混为同一分类。
19、spring中单例Bean是线程安全的吗?
参考回答:
单例并不等于线程不安全。关键是是否存在未经保护的共享可变状态:无状态服务通常可并发调用,有状态服务需要不可变设计、锁或并发工具等。改成prototype也不保证每个线程独享,尤其是只注入单例一次时。
20、SpringMVC的执行流程?
- 用户发送请求至前端控制器 DispatcherServlet。
- DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
- 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。
- DispatcherServlet 调用 HandlerAdapter 处理器适配器。
- HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller 执行完成返回 ModelAndView。
- HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet。
- DispatcherServlet 将 ModelAndView 传给 ViewResolver 视图解析器。
- ViewResolver 解析后返回具体 View。
- DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet 响应用户。
以上是视图渲染路径。对于@ResponseBody或@RestController,返回值由HttpMessageConverter按媒体类型写入响应体,通常不经过视图解析,不是所有Controller都返回ModelAndView。参见官方@ResponseBody。


21、解释一下DispatcherServlet的作用?(了解)
- DispatcherServlet是Spring MVC的前端控制器,它负责接收匹配其Servlet映射的HTTP请求,并根据请求的类型和内容,将请求分发到相应的Controller进行处理。同时,它也负责将Controller返回的结果传递给视图进行渲染。
22、Spring MVC的主要组件?(了解)
- Spring MVC的主要组件包括DispatcherServlet(前端控制器)
- HandlerMapping(处理器映射器)
- HandlerAdapter(处理器适配器)
- Controller(控制器)
- ModelAndView(模型和视图)
- ViewResolver(视图解析器)。
23、SpringMVC 的常用注解有哪些?
- @RequestMapping :用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径;
- @RequestBody :注解实现接收 HTTP 请求的 json 数据,将 json 转换为 Java对象;
- @ResponseBody :注解实现将 Controller 方法返回对象转化为 json 对象响应给客户
24、@Controller注解的作用?(了解)
在Spring MVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示。在Spring MVC 中提供了一个非常简便的定义Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用@Controller 标记一个类是Controller ,然后使用@RequestMapping 和@RequestParam 等一些注解用以定义URL 请求和Controller 方法之间的映射,这样的Controller 就能被外界访问到。此外Controller 不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,它们可以通过Controller 的方法参数灵活的获取到。
@Controller 用于标记在一个类上,使用它标记的类就是一个Spring MVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用@RequestMapping 注解的方法才是真正处理请求的处理器。单单使用@Controller 标记在一个类上还不能真正意义上的说它就是Spring MVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要我们把这个控制器类交给Spring 来管理。有两种方式:
在Spring MVC 的配置文件中定义MyController 的bean 对象。
在Spring MVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。
25、Spring事务的实现方式和原理以及隔离级别?
在使用Spring框架时,可以有两种使用事务的方式,一种是编程式的,一种是申明式的, @Transactional注解就是申明式的。
首先,事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行了扩展,以及提供了一些能让程序员更加方便操作事务的方式。
比如我们可以通过在某个方法上增加@Transactional注解,就可以开启事务,满足代理拦截条件后,使用同一事务资源的数据库操作可参与事务;新线程、独立数据源或REQUIRES_NEW等不能笼统视为同一事务。
在一个方法上加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么事务拦截器会委托事务管理器获取或创建事务(本地JDBC新事务通常关闭自动提交),然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交,若异常匹配回滚规则则回滚,未匹配的异常通常仍提交后向外抛出;加入已有事务时,最终物理提交由外层边界决定。
当然,针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的rollbackFor属性进行配置,默认情况下会对RuntimeException和Error进行回滚。
spring事务隔离级别:
ISOLATION_DEFAULT:这是个 PlatformTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
ISOLATION_READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据。
ISOLATION_READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已经提交的数据。
ISOLATION_REPEATABLE_READ:可重复读,防止脏读和不可重复读;按隔离级别定义仍可能有幻读,具体数据库实现可能提供更强保证,不能理解成所有查询永远一致。
ISOLATION_SERIALIZABLE:可串行化,保证并发执行效果等价于某个串行顺序,并不要求实现上事务逐个运行,可以通过锁或冲突检测实现。
继续阅读与资料
继续追问:事务何时真正提交,外部通知怎样避免提前执行。
