✅ 全覆盖核心考点:IoC、AOP、Spring 事务、SpringMVC、SpringBoot、Bean 生命周期 / 循环依赖 / 事务失效等高频坑点
✅ 答案均为「面试高分精简版」,分点清晰,突出核心要点,背诵即用,适合突击面试 / 查漏补缺
一、基础入门篇(初级 / 中级必问,面试保底分,重中之重)
1. Spring 是什么?核心优势有哪些?
答案要点
- Spring 是一站式轻量级Java 企业级开发框架,核心是简化开发,整合所有层的技术,生态完善(SpringMVC/SpringBoot/SpringCloud)。
- 核心优势(5 个核心):
- IoC 控制反转:把对象的创建 / 依赖注入交给容器管理,解耦层与层之间的依赖关系。
- AOP 面向切面编程:无侵入实现日志、事务、权限等公共功能,复用性极强。
- 声明式事务:一行注解完成事务控制,无需手动编写 try/catch 事务代码。
- 一站式开发:整合持久层(Mybatis)、Web 层(SpringMVC)、服务层,无缝衔接。
- 轻量级 & 低侵入:核心包体积小,API 简洁,无需继承 / 实现框架的类,对业务代码无侵入。
2. Spring 中 IoC 是什么?IoC 容器的作用是什么?
答案要点
- IoC = Inversion of Control 控制反转 :核心思想:将对象的创建权、对象之间的依赖关系,从业务代码中「反转」给 Spring 容器管理 。
- 传统开发:程序员手动
new 对象,自己维护依赖关系 → 耦合度极高。 - Spring 开发:程序员只需要定义对象,依赖关系由容器注入 → 完全解耦。
- 传统开发:程序员手动
- IoC 容器的核心作用:① 创建 Bean 对象 ② 管理 Bean 的生命周期 ③ 维护 Bean 之间的依赖注入(DI)。
- Spring 的 IoC 容器核心实现:
BeanFactory(顶层接口,基础实现)、ApplicationContext(功能增强版,开发首选)。
3. DI 依赖注入是什么?有哪几种注入方式?优缺点对比?
答案要点
- DI = Dependency Injection 依赖注入 :DI 是 IoC 的具体实现方式。容器在创建对象时,自动将依赖的对象注入到当前对象中,无需手动获取。
- 3 种核心注入方式(面试必考,必须说清区别):
- 构造器注入(Spring 官方推荐 ✅)
- 写法:通过类的有参构造注入,配合
@Autowired或 xml 的<constructor-arg>。 - 优点:注入的依赖不可变、不能为空,保证对象创建时依赖就初始化完成,安全性最高;解决循环依赖问题。
- 缺点:依赖过多时,构造方法参数会变多。
- 写法:通过类的有参构造注入,配合
- Setter 方法注入
- 写法:通过 setter 方法配合
@Autowired注入。 - 优点:注入灵活,支持选择性注入,适合可选依赖。
- 缺点:依赖对象可为空,对象创建后可被修改,存在安全风险。
- 写法:通过 setter 方法配合
- 字段注入(开发最常用,但不推荐 ❌)
- 写法:直接在成员变量上加
@Autowired,无需构造器 /setter。 - 优点:代码简洁,开发效率高。
- 缺点:无法注入 final 修饰的变量、依赖为空时会空指针、耦合度高、单元测试困难。
- 写法:直接在成员变量上加
- 构造器注入(Spring 官方推荐 ✅)
- ✅ 面试加分回答:生产环境优先用构造器注入,可选依赖用 Setter 注入,尽量避免字段注入。
4. Spring Bean 的生命周期?(高频中的高频,必背)
答案要点(8 步核心流程,按顺序背诵)
- 实例化:Spring 容器通过反射,创建 Bean 的实例对象(调用无参构造)。
- 属性注入:容器将依赖的 Bean 对象,注入到当前 Bean 的成员变量中(DI 核心步骤)。
- 执行 Aware 接口方法 :如果 Bean 实现了对应接口,执行回调:
BeanNameAware(获 Bean 名)、BeanFactoryAware(获容器)、ApplicationContextAware(获上下文)。 - 执行 BeanPostProcessor 前置处理 :全局的后置处理器,所有 Bean 都会执行,执行
postProcessBeforeInitialization。 - 执行初始化方法 :
- 自定义初始化方法:① 实现
InitializingBean接口 → 执行afterPropertiesSet()② 注解@PostConstruct③ xml 配置init-method。
- 自定义初始化方法:① 实现
- 执行 BeanPostProcessor 后置处理 :执行
postProcessAfterInitialization,AOP 的动态代理就是在这里生成的 ✅ 核心考点。 - Bean 就绪可用:Bean 完成初始化,存入容器的单例池,供业务调用。
- 销毁 Bean :容器关闭时执行销毁逻辑:① 实现
DisposableBean接口 → 执行destroy()② 注解@PreDestroy③ xml 配置destroy-method。
✅ 面试加分:BeanPostProcessor 是 Spring 扩展的核心,AOP、注解解析都是基于这个接口实现的。
5. Spring Bean 的作用域有哪些?默认是哪个?
答案要点
- 共 5 种作用域,核心掌握前 4 种,默认作用域是:singleton 单例
-
singleton(单例,默认) :容器中只有一个 Bean 实例,全局共享,生命周期随容器启动 / 关闭。
- 适用:无状态的 Bean(Service、Dao、工具类),性能最优。
-
prototype(原型) :每次从容器中获取 Bean 时,都会创建一个新的实例 ,容器只负责创建,不负责销毁。
- 适用:有状态的 Bean(如用户请求的实体对象)。
-
request:每次请求创建一个单例对象,只在 web 环境有效,当处理请求结束,bean 对象将被销毁。
-
session:每次会话创建一个单例对象,只在 web 环境有效,当 HTTP Session 最终被废弃的时候,bean 对象也会被销毁。
-
global-session:一次集群环境的会话创建一个对象,只在 web 环境有效,当集群环境下的 session 销毁时,bean 对象也会被销毁。
✅ 面试坑点:单例 Bean 是线程不安全的,因为单例对象的成员变量会被多线程共享,解决方案:① 避免定义成员变量 ② 用 ThreadLocal ③ 改用原型 Bean。
6. Spring 中 AOP 是什么?核心概念?应用场景?
答案要点
- AOP = Aspect Oriented Programming 面向切面编程 :核心思想是无侵入的对方法进行增强 ,将「业务逻辑」和「公共功能」分离。
- 业务逻辑:如订单创建、用户查询。
- 公共功能:如日志记录、事务控制、权限校验、异常处理 → 这些功能封装为「切面」。
- 核心概念(必须背会,面试必问)
- 切面 (Aspect):封装的公共功能模块(如日志切面、事务切面)。
- 连接点 (JoinPoint):程序执行的所有位置(所有方法),是切面可以切入的位置。
- 切入点 (Pointcut) :实际被增强的方法(连接点的子集),通过表达式指定(如 execution 表达式)。
- 通知 (Advice):切面的具体增强逻辑,分 5 种:前置 / 后置 / 返回 / 异常 / 环绕通知。
- 目标对象 (Target):被增强的业务类(如 OrderService)。
- 代理对象 (Proxy):AOP 动态生成的对象,是目标对象的增强版。
- AOP 的典型应用场景:日志记录、事务管理、权限校验、统一异常处理、接口性能监控、缓存控制。
二、进阶原理篇(中 / 高级必问,拉开面试差距,核心考点)
1. Spring AOP 的实现原理?JDK 动态代理 vs CGLIB 区别?(高频必考)
答案要点
✔ 核心原理
Spring AOP 基于动态代理 实现,在 Bean 生命周期的BeanPostProcessor后置处理阶段,动态生成目标对象的代理对象,所有方法调用都会经过代理对象,从而实现无侵入增强。
核心前提:Spring AOP 只能对方法级别的增强,不能增强属性 / 构造器。
✔ 两种动态代理方式(面试必考,必须说清区别 + 使用场景)
-
JDK 动态代理(默认)
- 实现条件:目标对象必须实现一个或多个接口。
- 原理:通过反射生成「接口的代理类」,代理类实现目标接口,重写所有方法,在方法中嵌入增强逻辑。
- 优点:JDK 原生支持,无需依赖第三方包,效率高。
- 缺点:必须实现接口,否则无法使用。
-
CGLIB 动态代理(字节码增强)
- 实现条件:目标对象无需实现接口,底层依赖 ASM 字节码框架。
- 原理:通过生成「目标对象的子类」,重写父类的方法,在子类中嵌入增强逻辑。
- 优点:无需实现接口,适用范围更广。
- 缺点:不能增强
final修饰的类 / 方法(final 类不能被继承),效率略低于 JDK 代理(JDK8 后差距极小)。
✔ Spring 的自动选择规则
✅ 必背:目标对象有接口 → 用 JDK 动态代理;目标对象无接口 → 用 CGLIB 代理 。手动指定代理方式:配置
proxy-target-class=true强制使用 CGLIB。
2. Spring AOP 的 5 种通知类型,执行顺序?
答案要点(5 种通知,按执行顺序背诵)
- 前置通知(@Before) :目标方法执行之前执行,不能阻止目标方法执行。
- 环绕通知(@Around,核心) :目标方法执行前后 都能增强,可以控制目标方法是否执行,甚至修改返回值,功能最强,开发中最常用。
- 后置通知(@After) :目标方法执行之后执行,无论方法是否抛出异常,都会执行。
- 返回通知(@AfterReturning) :目标方法正常返回后执行,可获取方法的返回值,异常时不执行。
- 异常通知(@AfterThrowing) :目标方法抛出异常后执行,可获取异常信息,正常返回时不执行。
✅ 面试加分:环绕通知是重中之重,因为它能完全控制目标方法的执行流程。
3. Spring 事务的核心知识点:隔离级别 + 传播机制(面试必考,重中之重)
✔ 一、事务的 4 个特性(ACID):必背
- 原子性 (Atomic):事务中的操作要么全成功,要么全回滚。
- 一致性 (Consistent):事务执行前后,数据的完整性不变。
- 隔离性 (Isolated):多个事务并发执行时,相互隔离,互不影响。
- 持久性 (Durable):事务提交后,数据永久写入数据库,不会丢失。
✔ 二、Spring 的事务隔离级别(共 5 种,核心 4 种)
- 隔离级别解决的问题:并发事务带来的脏读、不可重复读、幻读。
- Spring 的默认隔离级别:ISOLATION_DEFAULT → 继承数据库的默认隔离级别(MySQL 默认:可重复读 RR)。
- 读未提交(READ_UNCOMMITTED):最低级别,能读到其他事务未提交的数据 → 存在脏读、不可重复读、幻读。
- 读已提交(READ_COMMITTED):只能读到其他事务已提交的数据 → 解决脏读,存在不可重复读、幻读。(Oracle 默认)
- 可重复读(REPEATABLE_READ):同一个事务中,多次读取同一数据,结果一致 → 解决脏读、不可重复读,存在幻读。(MySQL 默认 ✅)
- 串行化(SERIALIZABLE):最高级别,事务串行执行,完全无并发 → 解决所有问题,但是性能极差,几乎不用。
✔ 三、Spring 的事务传播机制(共 7 种,重点背会 4 个常用的,面试必问)
✅ 核心定义:当一个事务方法调用另一个事务方法时,如何处理事务的行为 ,这是 Spring 独有的特性,数据库没有传播机制。所有传播机制注解:
@Transactional(propagation = Propagation.XXX)
- REQUIRED(默认,必须掌握 ✅) :如果当前有事务,就加入事务;如果没有,就新建一个事务。
- 适用场景:绝大多数业务(如订单创建、库存扣减),增删改必用。
- 特点:子方法和父方法共用一个事务,只要有一个方法失败,全部回滚。
- REQUIRES_NEW(必须掌握 ✅) :无论当前是否有事务,都新建一个独立的事务 ,新事务和原事务互不影响。
- 适用场景:日志记录、消息发送、积分增加等「非核心业务」,即使失败也不影响主业务。
- 特点:子方法事务失败,不会回滚父方法;父方法失败,也不会回滚子方法。
- SUPPORTS:如果当前有事务,就加入事务;如果没有,就以非事务方式执行。(适用:查询方法)
- NESTED(嵌套事务):如果当前有事务,就嵌套在当前事务中执行;如果没有,就新建事务。子事务失败,只回滚子事务,不回滚父事务;父事务失败,全部回滚。
4. Spring 声明式事务失效的 8 种场景(高频坑点,面试必问,背会加分)
答案要点 :声明式事务是基于 @Transactional 注解实现,底层是 AOP 动态代理,所有失效场景都围绕 AOP 失效 / 注解使用不当,按高频度排序:
✅ 失效场景 1:注解加在非 public 修饰的方法上 → 最常见
- 原因:Spring AOP 只对 public 方法生成代理,private/protected/default 方法加注解无效。
✅ 失效场景 2:同一个类中,无事务方法调用有事务方法 → 超级高频
- 原因:内部调用,没有走代理对象,而是直接调用原对象方法,AOP 无法拦截。
✅ 失效场景 3:事务方法抛出非 RuntimeException 异常
- 原因:Spring 默认只对RuntimeException 和 Error回滚,自定义异常 / IOException 不会回滚。
- 解决:
@Transactional(rollbackFor = Exception.class)手动指定回滚异常。
✅ 失效场景 4:方法内部手动捕获了异常,没有抛出
- 原因:事务管理器感知不到异常,无法触发回滚。
- 解决:捕获异常后,手动抛出
throw new RuntimeException(e)。
✅ 失效场景 5:注解的传播机制配置错误
- 如配置了
propagation = Propagation.NOT_SUPPORTED(不支持事务),注解直接失效。
✅ 失效场景 6:目标对象不是 Spring 容器的 Bean
- 原因:事务是基于 Spring 容器的 Bean 生成代理,手动 new 的对象,Spring 无法管理。
✅ 失效场景 7:数据库本身不支持事务
- 如 MySQL 的 MyISAM 引擎,不支持事务,用 InnoDB 引擎即可。
✅ 失效场景 8:只读事务配置错误
@Transactional(readOnly = true)是只读事务,执行增删改操作,事务失效。
5. Spring 如何解决 Bean 的循环依赖?(高频必考,源码级问题)
答案要点
✔ 什么是循环依赖?
两个 / 多个 Bean 互相依赖对方,如:A依赖B,B又依赖A 或 A→B→C→A,Spring 容器启动时,如果不处理,会出现死循环。
注意:Spring 只解决「单例 Bean 的构造器之外的循环依赖」,原型 Bean 的循环依赖、单例 Bean 的构造器注入循环依赖 → Spring 无法解决,直接报错。
✔ 核心解决方案:三级缓存机制(必背,面试加分核心)
Spring 通过在DefaultSingletonBeanRegistry中维护3 个缓存 Map ,彻底解决循环依赖,缓存顺序:一级缓存 > 二级缓存 > 三级缓存
- 一级缓存(单例池)singletonObjects :存放完全初始化完成的 Bean,可直接使用(最终状态)。
- 二级缓存(早期对象池)earlySingletonObjects :存放实例化完成、未完成属性注入和初始化的 Bean(半成品对象)。
- 三级缓存(工厂池)singletonFactories :存放Bean 的工厂对象,用于生成 Bean 的早期代理对象(解决 AOP 代理的循环依赖)。
✔ 核心流程(简化版,面试够用)
- 容器创建 A,完成实例化,将 A 的工厂对象放入三级缓存。
- 给 A 注入依赖 B,发现 B 不存在,容器创建 B,完成实例化,将 B 的工厂对象放入三级缓存。
- 给 B 注入依赖 A,从三级缓存中取出 A 的工厂,生成 A 的早期对象,放入二级缓存,并删除三级缓存。
- B 完成属性注入和初始化,放入一级缓存,删除二级缓存。
- A 拿到 B 的实例,完成属性注入和初始化,放入一级缓存,删除二级缓存。
✅ 面试加分:为什么不用二级缓存?因为要解决AOP 代理的循环依赖,三级缓存的工厂可以动态生成代理对象,二级缓存做不到。
6. SpringMVC 的执行流程(10 步,高频必考,必背)
答案要点(按顺序背诵,标准 10 步,面试满分答案)
- 用户发起 Http 请求,请求被前端控制器 DispatcherServlet 接收(核心入口,中央调度器)。
- DispatcherServlet 根据请求 URL,调用 HandlerMapping 处理器映射器,获取对应的 Handler(Controller 方法)。
- HandlerMapping 返回一个HandlerExecutionChain(包含 Handler + 拦截器)给 DispatcherServlet。
- DispatcherServlet 调用 HandlerAdapter 处理器适配器,适配当前的 Handler。
- HandlerAdapter 执行 Handler(Controller 的业务方法),并返回一个 ModelAndView(数据模型 + 视图名)。
- 执行完 Controller 方法后,会经过拦截器的后置处理方法。
- DispatcherServlet 调用 ViewResolver 视图解析器,将 ModelAndView 中的视图名解析为具体的 View 视图对象(如 jsp/html)。
- ViewResolver 返回解析后的 View 给 DispatcherServlet。
- DispatcherServlet 调用 View 的render 方法,将 Model 数据渲染到视图中,生成响应页面。
- DispatcherServlet 将响应结果返回给用户,请求结束。
✅ 核心组件记忆:前端控制器、映射器、适配器、解析器 → 四大核心组件完成所有流程。
三、高级源码 & 实战篇(资深 / 架构师必问,高薪考点,拔高面试档次)
1. BeanFactory 和 ApplicationContext 的区别?(源码高频)
答案要点
- 两者都是 Spring IoC 容器的核心接口,ApplicationContext 是 BeanFactory 的子接口,功能增强版。
- 核心定位
- BeanFactory:IoC 容器的顶层接口,只提供最基础的 Bean 创建、获取功能,是「最小化容器」。
- ApplicationContext:基于 BeanFactory 扩展,提供了全部 BeanFactory 的功能 + 海量增强功能,开发中唯一使用的容器。
- 核心区别(面试必答) ✔ 初始化方式:BeanFactory 是懒加载 (获取 Bean 时才创建);ApplicationContext 是饿加载(容器启动时就创建所有单例 Bean)。✔ 功能支持:ApplicationContext 支持国际化、事件发布、资源加载、AOP、注解驱动,BeanFactory 都不支持。✔ 开发场景:BeanFactory 适合嵌入式设备 / 内存受限场景;ApplicationContext 适合所有企业级开发。
✅ 面试加分:ApplicationContext 的核心实现类:
ClassPathXmlApplicationContext(xml 配置)、AnnotationConfigApplicationContext(注解配置)。
2. @Autowired 和 @Resource 的区别?(高频坑点,必背)
答案要点(面试必考,分点清晰,满分答案)
- 来源不同 :
@Autowired:Spring原生注解,属于 Spring 框架。@Resource:JDK原生注解(JSR250),Java 标准,非 Spring 独有,其他框架也支持。
- 注入规则不同(核心区别 ✅) :
@Autowired:先按类型(byType)注入 ,类型匹配失败则按名称(byName)注入;支持@Qualifier注解指定 Bean 名称。@Resource:先按名称(byName)注入 ,名称匹配失败则按类型(byType)注入;可通过name属性指定 Bean 名称。
- 支持的注解属性不同 :
@Autowired:支持required=false(注入失败不报错)。@Resource:支持name/type属性,不支持required=false。
- 注入范围不同 :
@Autowired:可注入构造器、方法、字段、参数。@Resource:只能注入字段、setter 方法。
✅ 开发建议:推荐用 @Resource,解耦 Spring 框架,兼容性更好;需要按类型注入时用 @Autowired+@Qualifier。
3. SpringBoot 核心优势?和 Spring 的区别?(面试必问,现在面试都结合 Boot)
✔ SpringBoot 核心优势(核心:约定大于配置)
- 自动装配:核心特性,无需手动配置 xml,自动加载框架的默认配置,极大简化开发。
- 起步依赖:将相关依赖打包成一个 starter(如 spring-boot-starter-web),一键引入,解决依赖版本冲突。
- 内嵌容器:内置 Tomcat/Jetty/Undertow,无需部署到外部容器,直接 jar 包运行。
- 简化配置:支持 yml/yaml 配置文件,替代 xml,配置更简洁;支持环境隔离(dev/test/prod)。
- 监控运维:内置 Actuator,可监控应用健康状态、接口调用情况,方便运维。
- 无代码生成、无 xml 配置:纯注解驱动,对业务代码无侵入。
✔ Spring vs SpringBoot(本质区别)
- Spring 是核心框架,提供 IoC/AOP/ 事务等基础能力,但配置繁琐,需要手动整合各种组件。
- SpringBoot 是Spring 的脚手架 ,基于 Spring 开发,封装了 Spring 的所有功能,核心是简化配置、快速开发。
✅ 一句话总结:SpringBoot 不是替代 Spring,而是让 Spring 用起来更简单。
4. SpringBoot 自动装配的核心原理?(高薪考点,源码级)
答案要点(精简版,面试够用,不啰嗦)
- 核心注解:
@SpringBootApplication是组合注解,核心依赖 3 个:@SpringBootConfiguration:本质是@Configuration,标识配置类。@ComponentScan:扫描当前包及子包的 @Component 注解的类。@EnableAutoConfiguration:自动装配的核心注解 ✅。
@EnableAutoConfiguration引入了AutoConfigurationImportSelector类,该类通过 SPI 机制,加载 META-INF 下的spring.factories文件。spring.factories文件中配置了所有需要自动装配的自动配置类(AutoConfiguration),如 WebMvcAutoConfiguration、RedisAutoConfiguration。- 每个自动配置类都有
@Conditional条件注解,只有满足条件(如引入了对应的依赖),才会生效。 - 自动配置类会给容器中注入默认的 Bean,如 RedisTemplate、RestTemplate,无需手动配置。
✅ 面试加分:自动装配的核心是「条件注解 + SPI 机制」,按需加载配置,这是 SpringBoot 的灵魂。
5. Spring 项目性能优化的常用手段?(实战高频,架构师必问)
答案要点(分维度整理,全面且有条理,面试满分)
✔ 一、容器层面优化
- 开启 Spring 的懒加载 :对非核心 Bean 设置
lazy-init=true,减少容器启动时间,节省内存。 - 减少 Bean 的作用域:非必要不使用原型 Bean,单例 Bean 性能最优。
- 关闭无用的自动配置:SpringBoot 中用
@SpringBootApplication(exclude = xxx.class)排除无用的自动配置类。
✔ 二、代码层面优化
- 避免单例 Bean 的线程安全问题:尽量不在单例 Bean 中定义成员变量,必须用则用 ThreadLocal。
- 合理使用 AOP:避免过度使用 AOP,尤其是环绕通知,会增加方法调用开销。
- 优化事务粒度:事务注解加在最小粒度的方法上,避免大事务导致的锁等待、性能下降。
✔ 三、依赖层面优化
- 按需引入依赖:避免引入无用的 starter,减少 jar 包体积和类加载时间。
- 统一依赖版本:用 SpringBoot 的父工程统一管理依赖版本,避免版本冲突。
✔ 四、其他优化
- 开启编译期注解处理:减少运行时反射开销。
- 合理使用缓存:对高频查询接口,用 Spring Cache+Redis 做缓存,减少数据库查询。
- 异步处理:对非核心业务(如日志、消息发送),用
@Async注解实现异步调用,提升接口响应速度。
✅ 面试总结(加分小技巧)
- Spring 面试的核心是 IoC+AOP + 事务 + SpringMVC,这四个模块占比 90%,吃透即可应对绝大多数面试。
- 回答问题时,分点作答,逻辑清晰,比如 Bean 生命周期、SpringMVC 流程,按顺序说,面试官会觉得你基础扎实。
- 遇到源码问题(如循环依赖、自动装配),不用讲太细的源码,讲清楚核心原理即可,面试官要的是你的理解能力,不是背诵源码。