Spring IOC:Bean 创建流程全解析(从 getBean 到 AOP 代理生成)
想把 Spring IOC 讲清楚,核心就一句话:Spring 在你调用 getBean() 或容器启动预实例化单例时,会按固定生命周期把"BeanDefinition 图纸"加工成"可用 Bean(可能是代理)",并放进单例池。
本文围绕 Bean 创建主链路 讲透:创建入口、生命周期步骤、关键扩展点(BFPP/BPP)、AOP 代理生成点、循环依赖的插入位置,帮助你达到"能讲"的水平。
0. 先明确两个对象:BeanDefinition vs Bean
- BeanDefinition:Bean 的"图纸"(类名、scope、依赖、初始化方法、是否懒加载等)。容器启动时已解析并注册好。
- Bean 实例:运行期的对象(你最终注入/拿到的对象,可能是原始对象,也可能是代理对象)。
1. Bean 是什么时候被创建的?
两种典型时机:
- 容器启动阶段 :创建所有 非 lazy 的单例
发生在finishBeanFactoryInitialization()里(本质是循环调用getBean())。 - 运行时按需创建 :你第一次
getBean(),或注入触发创建(依赖链)
典型:某个 Bean 是@Lazy、或 scope=prototype。
2. 主入口:doGetBean(拿 Bean 的总入口)
当你调用 getBean("xxx"),最终会走到:
AbstractBeanFactory#doGetBean
它会做几件大事(逻辑上):
- 先查缓存(单例池里是否已有成品)
- 没有就创建 (走
createBean/doCreateBean) - 处理依赖(dependsOn、循环依赖、FactoryBean 等)
- 返回最终对象(可能是代理,也可能是 FactoryBean 产物)
3. Bean 创建核心:doCreateBean("生产线")
Spring 创建一个普通 Bean(非 FactoryBean)的核心流程在:
AbstractAutowireCapableBeanFactory#doCreateBean
可以用四段来记:
实例化 Instantiation → 属性填充 Populate → 初始化 Initialization → 注册销毁 Destroy
下面逐段展开。
4. 第一步:实例化(Instantiation)------"造出毛坯房"
4.1 发生了什么?
Spring 会根据 BeanDefinition 决定怎么 new 对象:
- 构造器注入 / 无参构造
- 工厂方法(
@Bean、Factory Method) - Supplier(函数式创建)
最终得到一个 原始对象 rawBean:属性大多还是默认值 / null。
4.2 关键点:实例化后,可能"提前暴露引用"
如果是 单例 + 允许循环依赖,Spring 会在属性填充前做一件重要的事:
- 把一个
ObjectFactory放入三级缓存singletonFactories - 允许别的 Bean 在循环依赖场景下拿到"早期引用"(可能触发提前代理)
注意:这一步不等于把 Bean 放进一级缓存,它只是提供"可能用得上的早期引用"。
5. 第二步:属性填充(PopulateBean)------"装修+装家具"
5.1 发生了什么?
Spring 会把依赖注入进来:
@Autowired/@Resource/@Value- XML property
- 自动装配 byType/byName
注入过程中如果发现依赖 Bean 没有创建,会递归触发依赖 Bean 的创建(依赖链就是在这里展开的)。
5.2 循环依赖通常在这里被触发
典型 setter 循环依赖:
- A 填充属性需要 B → 创建 B
- B 填充属性需要 A → 此时 A 还没完成
Spring 会尝试从三级缓存 ObjectFactory拿到 A 的早期引用 → 注入给 B → 打破循环
6. 第三步:初始化(Initialization)------"通电自检 + 功能增强"
初始化阶段发生在 initializeBean() 中,是面试最容易问深的部分。它的顺序非常固定:
6.1 Aware 回调(让 Bean "认识容器")
如果 Bean 实现了这些接口,Spring 会注入相关上下文:
BeanNameAwareBeanClassLoaderAwareBeanFactoryAwareApplicationContextAware(通过ApplicationContextAwareProcessor)
6.2 BeanPostProcessor Before
执行所有 BeanPostProcessor#postProcessBeforeInitialization(bean, beanName):
- 常见:处理
@PostConstruct的前置准备等
6.3 执行初始化方法(init callbacks)
按顺序可能包含:
@PostConstructInitializingBean#afterPropertiesSetinit-method(XML 或@Bean(initMethod=...))
6.4 BeanPostProcessor After(极其重要:AOP 代理通常在这里生成)
执行所有 BeanPostProcessor#postProcessAfterInitialization(bean, beanName)。
AOP(以及事务)通常就是在这个阶段把原始对象替换成代理对象的。
- 负责 AOP 的典型处理器:
AnnotationAwareAspectJAutoProxyCreator - 它会判断当前 Bean 是否命中切点(Pointcut)
- 命中:创建 JDK/CGLIB 代理并返回 proxy
- 不命中:原样返回 bean
- Spring 使用"后置处理器的返回值"作为最终 Bean
=> 实现"偷梁换柱":rawBean 进去,proxyBean 出来
所以你注入的 Service 往往是
$Proxy...或xxx$$EnhancerBySpringCGLIB$$...。
7. 第四步:注册销毁回调(Destroy)------"贴上回收说明"
如果 Bean 是单例,且存在销毁逻辑,Spring 会注册:
DisposableBean#destroydestroy-method@PreDestroy
容器关闭(context.close())时统一调用。
8. 最终:进入单例池(一级缓存)
当 Bean 完全创建完成后(包含可能的代理替换):
- 放入
singletonObjects(一级缓存) - 同时清理早期缓存(如果曾发生循环依赖/提前暴露)
后续再次获取同名单例 Bean,直接从一级缓存返回。
9. 一张 ASCII 总览图(背诵友好)
text
getBean()
|
v
doGetBean()
|
+-- 命中 singletonObjects ? ----> return (成品/代理)
|
v
createBean()
|
v
doCreateBean()
|
+-- 1) 实例化 createBeanInstance() ---> rawBean
| |
| +-- (单例&允许循环依赖) addSingletonFactory() 放三级缓存
|
+-- 2) 属性填充 populateBean() -----> @Autowired 注入依赖
| |
| +-- 可能触发循环依赖:从三级缓存拿早期引用
|
+-- 3) 初始化 initializeBean()
| |
| +-- Aware 回调
| +-- BPP.before
| +-- init-method/@PostConstruct/afterPropertiesSet
| +-- BPP.after ---> 【AOP/事务代理通常在这里生成】
|
+-- 4) 注册销毁回调 registerDisposableBeanIfNecessary()
|
v
addSingleton() 放入 singletonObjects(一级缓存)
return 最终对象(可能是 proxy)
10. 面试"能讲"的总结话术
Spring Bean 的创建核心分为四步:实例化、属性填充、初始化、销毁。
实例化阶段通过反射或工厂方法创建原始对象;属性填充阶段完成依赖注入并可能触发循环依赖处理;初始化阶段会执行 Aware、初始化方法以及 BeanPostProcessor。
AOP/事务代理通常在postProcessAfterInitialization里生成并替换原始对象 ,最后成品 Bean 放进一级缓存singletonObjects,后续直接复用。