Spring源码 第十二篇:Spring 全套核心原理 - 完结终章

我们循序渐进完整走完:IOC 容器 → Bean 生命周期 → 循环依赖 → AOP → 事务 → SpringMVC 全流程 → SpringBoot 自动配置 → 资源与环境配置 → 事件驱动 → 类型转换与参数校验 → 全套扩展点

从注解使用,到底层源码执行链路;从只会写业务,到能断点跟源码、懂底层原理、解线上 BUG。这一篇,做最终闭环收拢,干净收尾。

一、两大核心全链路 极简复盘

1. Spring IOC 容器启动流程

  1. 容器刷新 refresh()
  2. 扫描解析,全部资源转为 BeanDefinition
  3. 执行 BeanDefinitionRegistryPostProcessor 动态注册 Bean
  4. 执行 BeanFactoryPostProcessor 修改 Bean 定义
  5. 开始创建单例 Bean:构造器实例化 → 依赖注入(属性填充)
  6. BeanPostProcessor 前置处理(postProcessBeforeInitialization
  7. 执行初始化:@PostConstructInitializingBean.afterPropertiesSet() → 自定义 init-method
  8. BeanPostProcessor 后置处理(postProcessAfterInitialization,AOP 代理生成时机)
  9. 完整 Bean 存入单例池,容器刷新完成

核心口诀:先定义、后实例;先填充依赖,后前置处理;再初始化,最后后置处理并生成代理。

2. SpringMVC 请求执行全流程

  1. Tomcat 接收请求,委派 DispatcherServlet
  2. 核心方法 doDispatch 统一调度
  3. HandlerMapping 根据 URL 匹配 Controller 方法
  4. HandlerAdapter 适配当前处理器
  5. 拦截器 preHandle 按配置顺序执行
  6. 适配器内部:参数解析 → InvocableHandlerMethod.doInvoke 反射执行 Controller
  7. 处理器处理返回值、统一封装响应
  8. 拦截器 postHandle 按配置顺序的逆序执行
  9. 视图渲染(非 JSON 场景)
  10. preHandle 返回 true,触发 afterCompletion 逆向执行,进行资源清理

二、高频经典深坑

1. 循环依赖

  • Spring 仅支持:setter / 字段注入、单例 Bean
  • 不完全支持:构造器注入、多例 Bean、静态 Bean;代理 Bean 循环依赖部分支持,取决于代理创建方式
  • 核心解决方案:三级缓存 + 提前暴露半成品 Bean

2. AOP 失效核心原因

  1. 同类中 this.方法() 内部调用,不走代理(可通过 AopContext.currentProxy() 或自注入解决)
  2. 非 public / private / final / static 方法
  3. 对象手动 new,不受 Spring 容器管理
  4. 未开启动态代理、注解未扫描到

3. 事务失效核心原因

  1. 底层基于 AOP 代理,不走代理调用就没有事务
  2. 非 public 方法、同类内部调用
  3. 异常被 try-catch 捕获,事务框架感知不到异常,无法触发回滚
  4. 传播行为配置错误、数据库引擎不支持事务

4. 配置与 Environment

  • 所有配置最终都被封装为 PropertySource
  • 读取配置时从上到下遍历,后加入的配置优先级更高
  • SpringBoot 配置优先级:命令行 > 系统属性 > 环境变量 > 配置文件
  • 所有配置最终被封装为 PropertySource,后加入的 PropertySource 优先级更高
  • Spring Boot 完整配置优先级(从高到低):
    1. 命令行参数
    2. Java 系统属性
    3. 操作系统环境变量
    4. application-{profile}.properties/yml
    5. application.properties/yml
    6. @PropertySource 加载的配置

5. 注解注入与参数绑定

  • @Value@AutowiredAutowiredAnnotationBeanPostProcessor 处理,在属性填充阶段完成注入;@PostConstructCommonAnnotationBeanPostProcessor 处理,在初始化前置阶段执行
  • MVC 参数绑定 = 参数解析器 + 类型转换体系共同完成
  • @Valid 参数校验,依托统一 Validator 校验器

三、Spring 核心扩展点 汇总

按执行时机 & 用途精简总结:

扩展点 执行时机 核心用途
BeanDefinitionRegistryPostProcessor 容器早期执行 可动态新增 Bean 定义(ConfigurationClassPostProcessor 实现了此接口,完成配置类解析、扫描、@Import 等核心逻辑)
BeanFactoryPostProcessor Bean 定义加载完成后执行 可修改已有 Bean 定义
BeanPostProcessor Bean 初始化前后全局拦截增强 AOP 代理生成的核心依靠它(AbstractAutoProxyCreator);依赖注入也在其扩展接口 InstantiationAwareBeanPostProcessor 的支持下完成
InitializingBean / DisposableBean 单个 Bean 初始化/销毁时 自定义初始化、资源销毁回调
FactoryBean Bean 创建时 用于构建复杂、重型组装类 Bean,隐藏创建复杂逻辑。典型场景:整合 MyBatis 时创建 Mapper 代理对象、创建有复杂初始化逻辑的第三方 Bean
ImportSelector 配置类处理时立即执行 批量导入配置类
DeferredImportSelectorImportSelector 子接口) 延迟到所有配置类处理完毕后执行 SpringBoot 自动配置核心(AutoConfigurationImportSelector 实现了 DeferredImportSelector
ImportBeanDefinitionRegistrar 配置类处理时 手动编码注册 Bean,各种 @Enable 开关注解底层实现
ApplicationEvent 事件体系 运行时 发布订阅模式,业务解耦、框架内部解耦利器
SmartInitializingSingleton 在所有单例 Bean 都实例化完成后触发 用于执行容器启动完成后的全局回调逻辑,如预加载缓存、校验配置等

四、30 道 Spring 源码高频面试题

一、IOC & Bean 核心(1~8)

1. 什么是 IOC 控制反转、DI 依赖注入?

  • IOC:控制权反转,将对象创建、管理、依赖维护的权利,从开发者交给 Spring 容器。
  • DI:依赖注入,容器自动解析 Bean 之间的依赖,自动赋值,解耦代码。
  • 核心价值:降耦合、易扩展、便于统一管理 Bean 生命周期。

2. 简述 Spring Bean 完整生命周期?

BeanDefinition 加载 → 构造器实例化 → 依赖属性填充 → BeanPostProcessor 前置处理 → @PostConstructInitializingBean → 自定义 init 方法 → BeanPostProcessor 后置处理(生成代理) → 放入单例池 → 容器关闭执行销毁方法。

3. 三级缓存分别是什么?作用?

  • 一级缓存singletonObjects 完整成熟 Bean
  • 二级缓存earlySingletonObjects 半成品 Bean(已实例化未注入)
  • 三级缓存singletonFactories Lambda 工厂,提前暴露 Bean 引用

核心:通过三级缓存提前暴露引用,解决单例 Setter / 字段循环依赖。

4. 为什么不用二级缓存?构造器注入循环依赖为什么无解?

  • 二级缓存无法解决「循环依赖 + AOP 代理」场景;
  • 构造器注入:实例化就要依赖对象,没有半成品阶段,无法提前暴露,直接报错。

5. BeanFactory 和 ApplicationContext 区别?

  • BeanFactory:最顶层容器接口,懒加载、只负责 Bean 获取
  • ApplicationContext:继承 BeanFactory,具备国际化、事件发布、资源加载、自动扫描、完整生命周期管理。

6. Spring 单例 Bean 是线程安全的吗?

不安全。Spring 单例只保证容器中只有一份对象,不保证线程安全;不要在单例 Bean 中定义可变成员变量。

7. @Configuration、@Bean 底层原理?

配置类会被 ConfigurationClassPostProcessor 解析,Full 模式下配置类会被 CGLIB 代理,保证 @Bean 方法返回单例 Bean。

8. 原型 Bean 会被完整管理吗?

不会。多例 Bean 容器只负责创建,不会统一销毁,DisposableBean 不会执行。

二、AOP & 事务(9~15)

9. JDK 动态代理 和 CGLIB 代理区别

  • JDK 代理:基于接口,只能代理接口实现类
  • CGLIB 代理:基于子类继承,无需接口,可代理普通类
  • Spring 默认:有接口用 JDK,无接口用 CGLIB。

10. AOP 五种通知顺序?

前置通知 → 环绕前置 → 目标方法 → 环绕后置 → 后置通知 → 异常通知 → 最终通知。

11. 为什么 this 内部调用导致 AOP 失效?

this 是原生对象,不是 Spring 代理对象;AOP 增强全部在代理类中,原生调用不会走增强逻辑。解决:内部注入自身、通过代理对象调用。

12. Spring 事务底层原理?

基于 AOP 动态代理拦截目标方法;事务开启时,将数据库 Connection 绑定到当前线程;异常触发回滚,正常执行提交。

13. 事务传播行为核心区别

  • REQUIRED:有事务加入,无则新建
  • REQUIRES_NEW:无论有无,都新建独立事务
  • NESTED:嵌套事务,依赖父事务保存点,父回滚子全部回滚

14. 常见事务失效场景

非 public 方法、this 内部调用、异常被 try-catch 吃掉、传播行为配置错误、没有被 Spring 代理、引擎不支持事务。

15. 事务隔离级别

读未提交、读已提交、可重复读、串行化;Spring 可全局 / 方法级单独指定,解决脏读、不可重复读、幻读。

三、SpringMVC 核心(16~21)

16. DispatcherServlet 作用

SpringMVC 核心总调度器,接收所有请求,统一分发、匹配处理器、执行适配器、视图解析、统一响应。

17. HandlerMapping 和 HandlerAdapter 区别

  • HandlerMapping:根据 URL 查找 Controller 处理器
  • HandlerAdapter:适配不同处理器,执行目标方法

18. Controller 方法如何被执行?

adapter.handle() → 解析参数 → 调用 InvocableHandlerMethod.invokeForRequest → 最终执行 doInvoke → 反射执行目标 Controller 方法。

19. SpringMVC 参数绑定原理

请求原始字符串 → 参数解析器获取参数 → 调用 ConversionServiceFormatter 做类型转换 → 绑定到 Controller 方法入参。

20. 拦截器 和 Filter 区别

  • Filter:Servlet 原生,在最外层,控制所有请求
  • Interceptor:Spring 层级,在 Controller 前后,可使用 Spring 容器 Bean

21. @ResponseBody 实现原理

RequestResponseBodyMethodProcessor 处理,通过消息转换器(Jackson)将对象序列化为 JSON 直接写入响应流。

四、SpringBoot 自动配置 & 配置体系(22~26)

22. @SpringBootApplication 三大组成

  • @ComponentScan:包扫描
  • @SpringBootConfiguration:标记为配置类
  • @EnableAutoConfiguration:开启自动配置

23. 自动配置底层原理

@Import 导入 AutoConfigurationImportSelector,SPI 读取全部自动配置类,通过 @Conditional 条件注解按需加载。

24. spring.factories 与 imports 区别

  • SpringBoot 2.7 之前 :使用 spring.factories
  • 2.7 之后 :废弃工厂文件,使用 AutoConfiguration.imports 轻量化配置

25. @Conditional 系列注解作用

条件装配,满足类存在、Bean 存在、配置属性存在等条件,自动配置类才会生效,实现按需装配。

26. Spring 配置加载优先级(从高到低)

  1. 命令行参数
  2. 系统属性
  3. 系统环境变量
  4. 外部配置文件
  5. 项目内部 yml/properties
  6. 框架默认配置

五、扩展点 & 事件 & 综合(27~30)

27. BeanFactoryPostProcessor 和 BeanPostProcessor 区别

  • BeanFactoryPostProcessor :Bean 创建之前,修改 BeanDefinition
  • BeanPostProcessor:Bean 创建之后,对 Bean 实例增强、代理、注入

28. ImportSelector 与 ImportBeanDefinitionRegistrar

  • ImportSelector:批量导入配置类,自动配置核心
  • ImportBeanDefinitionRegistrar :手动编码注册 BeanDefinition,用于中间件接口扫描

29. Spring 事件驱动原理

基于发布订阅模式,ApplicationEventPublisher 发布事件,ApplicationListener@EventListener 监听消费;支持同步、异步、事务绑定事件,实现业务解耦。

30. 你用过哪些 Spring 扩展点?

实际常用:BeanPostProcessorWebMvcConfigurerHandlerInterceptor@EventListenerFactoryBeanImport 扩展,用来做统一增强、自定义配置、中间件整合、业务解耦。

相关推荐
AllData公司负责人1 小时前
亲测丝滑,体验跃迁|AllData通过集成开源项目RustFS,多模态数据存储新范式
java·大数据·数据库·算法·数据分析·rustfs
西安邮电大学2 小时前
2026华为OD机考真题附答案-准备生日礼物
java·后端
超梦dasgg2 小时前
Java 生产环境 RocketMQ 架构与部署指南
java·rocketmq·java-rocketmq
Trouvaille ~2 小时前
【Redis篇】Hash 哈希:字段级操作与对象存储的最佳实践
数据库·redis·后端·算法·缓存·哈希算法·键值对
cheems95272 小时前
JWT令牌是如何实现登录认证的
java
happyprince2 小时前
10-Hugging Face Transformers 量化系统深度分析
java·前端·数据库
budingxiaomoli2 小时前
利用Hutool完成验证码案例
java
山人在山上2 小时前
docker离线安装
java·docker·eureka