Spring 启动与加载过程

本文最后更新于 2025年6月25日 下午

Spring 本身是一套为服务提供管理和扩展的JAVA框架。为所有纳入它管理的对象(Bean) 提供注入,增强,初始化,生命周期管理等功能。其简单调用过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[BeanDefinition] 
通过注解/XML 声明的类的描述信息
↓
[createBean()]
创建ApplicationContext,由容器创建Bean对象
↓
[instantiateBean() → InstantiationStrategy.instantiate()]
创建裸对象
↓
[生成裸对象]
创建了目标Bean对象,但是Bean对象中的属性未初始化
↓
[加入三级缓存 (ObjectFactory)]
创建后将自己暴露到三级缓存中,通过ObjectFactory可以获取到处于创建过程中引用对象
↓
[属性填充 populateBean()]
向Bean中进行注入
↓
[BeanPostProcessor → AOP代理封装]
这一步将裸对象封装为动态代理,提供功能增强
↓
[放入一级缓存]
Bean完成初始化

循环依赖场景下的 Spring Bean 创建完整流程

Bean创建入口

1
2
3
4
5
6
7
8
↓
一级缓存 singletonObjects: 【最终对象】 → 检查是否存在?
↓
二级缓存 earlySingletonObjects: 【早期对象】 → 检查是否存在?
↓
三级缓存 singletonFactories: 【延迟工厂 ObjectFactory】 → 检查是否存在?
↓
【缓存都没有 → 开始实例化】

doCreateBean(beanName) 流程

1
2
3
4
5
6
7
8
9
1. 实例化裸对象 newInstance()
→ 裸对象 A@100 诞生(堆上地址)
↓
2. 注册三级缓存
singletonFactories.put(beanName, () -> getEarlyBeanReference(beanName, A@100))
→ 延迟执行的代理工厂
↓
3. 开始属性填充 populateBean()
→ 如果此时依赖了B,递归 getBean(B)

在B初始化时 getBean(A) 逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
B → getBean(A)
↓
一级缓存未命中
↓
二级缓存未命中
↓
三级缓存命中 → 执行 ObjectFactory
→ getEarlyBeanReference(beanName, A@100)
→ 判断是否需要AOP增强
→ 若需要 → 创建代理对象 Proxy(A)@300
→ 若不需要 → 返回 A@100
↓
把返回对象放入二级缓存 earlySingletonObjects.put(beanName, reference)

B 初始化完成 → 一级缓存

1
2
3
4
5
B 属性填充完成
↓
执行 BeanPostProcessor 初始化逻辑
↓
进入一级缓存 singletonObjects.put("B", 完整B对象)

A 继续完成初始化

1
2
3
4
5
6
7
8
9
10
11
12
A 继续属性填充,填入刚创建好的 B
↓
执行完整初始化 initializeBean()
↓
进入 postProcessAfterInitialization()
→ 二次判断是否已有代理(提前暴露已处理时)
是 → 直接返回已有代理
否 → 再次增强生成代理
↓
最终确定完整对象引用(裸对象或代理对象)
↓
进入一级缓存 singletonObjects.put("A", 最终A对象)

我们可以分析出 Spring 三级缓存 所存储内容的阶段

缓存级别 变量名 存储内容 作用时机
一级缓存 singletonObjects 完全初始化的Bean对象(最终对象) Bean完成所有初始化步骤后
二级缓存 earlySingletonObjects 提前暴露的Bean对象(早期对象) 解决循环依赖时,从三级缓存提升而来
三级缓存 singletonFactories ObjectFactory工厂对象 Bean实例化后立即放入,用于延迟创建代理

Spring 启动与加载过程
http://gadoid.io/2025/06/25/Spring-启动与加载过程/
作者
Codfish
发布于
2025年6月25日
许可协议