【Spring源码】万字长文,带你图解 Spring 核心流程 `refresh()` (含循环依赖与 AOP 原理)
万字长文,带你图解 Spring 核心流程
前言
Spring 框架是 Java 开发者的基石,而 AbstractApplicationContext.refresh() 方法则是这块基石的心脏。无论是 Spring MVC、Spring Boot 还是普通的 Spring 应用,容器的启动过程最终都会调用到这个方法。
很多人觉得 Spring 源码晦涩难懂,实际上只要抓住 “一条主线(refresh)” 和 “几个关键扩展点(PostProcessor)”,就能化繁为简。
本文将通过图解的方式,深入剖析 refresh() 的全流程,并重点拆解 Bean 的生命周期、三级缓存解决循环依赖以及 AOP 代理的生成时机。
一、 refresh():容器启动的总指挥
refresh() 方法定义在 AbstractApplicationContext 中,它定义了整个容器初始化的标准模板。无论你使用的是 XML 配置还是注解配置,流程都是一样的。
1.1 核心流程图
1.2 源码概览
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备工作
prepareRefresh();
// 2. 获取 BeanFactory (加载 BeanDefinition)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备 BeanFactory (设置 ClassLoader, Aware 接口支持等)
prepareBeanFactory(beanFactory);
try {
// 4. 子类扩展点
postProcessBeanFactory(beanFactory);
// 5. 调用 BeanFactoryPostProcessor (解析 @Configuration, @ComponentScan)
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor (AOP 的基石)
registerBeanPostProcessors(beanFactory);
// 7. 初始化国际化
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 子类扩展点 (Spring Boot 在这里启动 Tomcat)
onRefresh();
// 10. 注册监听器
registerListeners();
// 11. 【核心】实例化所有非懒加载单例 Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新,发布事件
finishRefresh();
} catch (BeansException ex) {
// 异常处理...
}
}
}
二、 核心重头戏:Bean 的生命周期
在第 11 步 finishBeanFactoryInitialization 中,Spring 会遍历所有的 BeanDefinition,通过 getBean() -> doCreateBean() 来创建对象。
这不是简单的 new,而是一个复杂的流水线工程。
2.1 Bean 创建流水线
关键点解析:
- Instantiation (实例化): 仅仅是在堆内存中申请空间,对象属性都是默认值(null)。
- Populate (属性填充): 也就是依赖注入(DI),递归调用
getBean获取依赖对象。 - Initialization (初始化): 执行用户自定义的初始化逻辑,以及 AOP 代理的生成(通常在
postProcessAfterInitialization)。
三、 难点攻克:三级缓存与循环依赖
假设 A 依赖 B,B 依赖 A。Spring 是如何解决死锁的?
答案是:三级缓存。
- 一级缓存 (
singletonObjects): 存放完整的、初始化好的 Bean。 - 二级缓存 (
earlySingletonObjects): 存放半成品 Bean(已实例化,未属性填充)。 - 三级缓存 (
singletonFactories): 存放ObjectFactory(Lambda 表达式),用于生成 Bean 的早期引用(可能是代理对象)。
3.1 循环依赖解决流程
3.2 为什么需要三级缓存?
如果不考虑 AOP,二级缓存就够了。但如果 A 被 AOP 代理了,B 注入的必须是 A 的代理对象,而不是原始对象。
三级缓存中的工厂 getEarlyBeanReference 保证了:只有在发生循环依赖时,才提前通过 AOP 创建代理对象;否则,AOP 代理依然推迟到初始化最后一步进行。
四、 AOP 代理的秘密
AOP 代理对象到底是在什么时候创建的?很多人会误以为只有一种情况,其实分两种:
- 正常情况:
- 在 Bean 初始化后 (
postProcessAfterInitialization) 创建。 - 源码类:
AbstractAutoProxyCreator。
- 循环依赖情况:
- 在 Bean 实例化后、属性填充前 (通过三级缓存的
getEarlyBeanReference) 提前创建。 - 为了防止重复代理,Spring 使用
earlyProxyReferences集合记录了已经提前代理的 Bean。
五、 总结
看懂 Spring 源码,本质上就是看懂 对象的管理艺术:
- refresh() 是骨架,定义了容器启动的标准流程。
- BeanDefinition 是图纸,描述了 Bean 应该长什么样。
- BeanPostProcessor 是工匠,在 Bean 创建的各个阶段进行精修(AOP、注解处理)。
- 三级缓存 是应急通道,巧妙解决了循环引用的死结。
希望这篇图解能帮你打破对 Spring 源码的恐惧!
面试题自测:
BeanFactory和FactoryBean有什么区别?- Spring 为什么不能解决构造函数参数的循环依赖?
@Autowired和@Resource在源码层面有什么区别?
(欢迎在评论区留言讨论!)
更多推荐




所有评论(0)