ARTICLE · 1326017
死磕 Spring 6.0 源码:一张流程图,彻底揭开 Bean 初始化与 AOP 的神秘面纱
在 Java 后端面试中,Spring Bean 的生命周期几乎是必考题。很多候选人只能干巴巴地背出“实例化、属性赋值、初始化”这三个词。
但如果面试官追问:“Spring 是如何解决循环依赖的?”或者“Spring 的 AOP 代理到底是在哪个阶段生成的?”,大部分人就哑火了。
今天,我们结合 Spring 6.0 的源码,配合核心执行流程图,深入 Spring 容器的黑盒内部,彻底搞懂 Bean 从实例化到完成初始化的底层真相。
说明:以下代码为便于公众号阅读有简化,完整源码请参考 Spring 6.0 的 AbstractAutowireCapableBeanFactory。
01一、核心概念辨析:实例化 vs 属性赋值 vs 初始化
在深入源码前,必须厘清三个极易混淆的概念:
1. 实例化(Instantiation)
createBeanInstance()。通常通过无参构造器、带参构造器或工厂方法实现。2. 属性赋值(Populate)
@Autowired、@Resource、XML <property> 等依赖写入字段。populateBean()。3. 初始化(Initialization)
BeanPostProcessor 前后置、初始化方法,以及 AOP 代理生成。initializeBean()。⚠️ 关键校准:属性赋值和初始化都属于创建阶段,但它们是两个独立步骤。populateBean() 在 initializeBean() 之前执行,不是 initializeBean() 内部的一部分。本文重点拆解的是 initializeBean() 的四部曲。
02二、实例化:空壳对象的诞生
Spring 是如何创建这个空对象的?来看 createBeanInstance 的核心逻辑。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 实例化阶段完成// 判断是否需要提前暴露:单例、允许循环引用、当前正在创建boolean earlySingletonExposure = mbd.isSingleton()&& this.allowCircularReferences&& isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {// 将半成品 Bean 包装成 ObjectFactory,放入三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 属性赋值populateBean(beanName, mbd, instanceWrapper);// 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;}
核心点:在这一步,Spring 只是通过反射或 CGLIB 创建了一个普通 Java 对象。它甚至不知道自己属于哪个 Spring 容器,字段也还没有被注入。
03三、初始化前夜:三级缓存与循环依赖
实例化完成后,紧接着是属性赋值。但在 populateBean 执行之前,Spring 做了一件极其精妙的事情:提前暴露半成品。这是解决循环依赖的核心。
在 doCreateBean 中,有这样一段关键逻辑:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {// 实例化阶段完成// 判断是否需要提前暴露:单例、允许循环引用、当前正在创建boolean earlySingletonExposure = mbd.isSingleton()&& this.allowCircularReferences&& isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {// 将半成品 Bean 包装成 ObjectFactory,放入三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 属性赋值populateBean(beanName, mbd, instanceWrapper);// 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;}
Spring 6.0 中三级缓存的数据结构如下:
// 一级缓存:存放已经初始化完成的单例 Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:存放早期的单例 Bean,可能已经是 AOP 代理private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:存放用于提前暴露的工厂 ObjectFactoryprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
为什么需要 getEarlyBeanReference?
假设 A 依赖 B,B 又依赖 A。
ObjectFactory 放入三级缓存;ObjectFactory,调用 getObject(),也就是 getEarlyBeanReference;⚠️ 边界校准:只有需要 AOP 代理的 Bean,才会在 getEarlyBeanReference 阶段提前生成早期代理;普通 Bean 的早期引用仍是原始对象。后续 postProcessAfterInitialization 会检测是否已提前生成代理,避免重复创建。
⚠️ 版本提醒:Spring Boot 2.6+ 默认禁止循环依赖,字段注入也可能直接启动失败。本文讲的是传统允许循环依赖场景下的三级缓存机制;生产环境更推荐通过重构消除循环依赖,而不是依赖三级缓存兜底。
04四、初始化四部曲:打磨最终的“完全体”
属性赋值完成后,Spring 进入 initializeBean 阶段。这里发生的就是初始化四部曲。

protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {// 1. Aware 接口回调:让 Bean 感知 Spring 容器invokeAwareMethods(beanName, bean);Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 2. 前置处理器:处理 @PostConstruct 等注解wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 3. 执行自定义初始化方法:InitializingBean 或 init-methodinvokeInitMethods(beanName, wrappedBean, mbd);} catch (Throwable ex) {throw new BeanCreationException(beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 4. 后置处理器:AOP 代理生成的最终战场wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
Step 1:Aware 接口回调
如果 Bean 实现了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 等接口,Spring 会通过 invokeAwareMethods 将容器信息注入给 Bean。
⚠️ 严谨细节:ApplicationContextAware不是在这里触发的,它由 ApplicationContextAwareProcessor 这个 BeanPostProcessor 在初始化前置处理阶段注入。
Step 2:前置处理器
Spring 会遍历所有 BeanPostProcessor,执行 postProcessBeforeInitialization。
我们常用的 @PostConstruct 注解,就是由 CommonAnnotationBeanPostProcessor 在这一步负责解析并调用的。
Step 3:执行自定义初始化
InitializingBean 接口,会调用其 afterPropertiesSet();@Bean(initMethod = "init") 配置了初始化方法,也会在此时触发;afterPropertiesSet(),再自定义 init-method。Step 4:后置处理器与 AOP 生成(核心)
这是 Spring AOP 魔法发生的地方。
Spring 会在此时触发 AbstractAutoProxyCreator 的 postProcessAfterInitialization。它会判断当前 Bean 是否匹配了切面(Aspect)。如果匹配,Spring 会利用 JDK 动态代理或 CGLIB,在这里将原始 Bean 替换为 AOP 代理对象。
注意:此时方法返回的 wrappedBean 已经不再是原始 Java 对象,而是一个被 Spring 包装过的、带有拦截器链的代理对象。

05五、完整流程总结
通过源码级拆解,Spring Bean 的初始化流程可以总结为:
ObjectFactory 放入三级缓存;必要时(涉及 AOP)提前生成早期代理放入二级缓存。populateBean() 完成依赖注入,如 @Autowired。@PostConstruct、自定义初始化方法,最后在 postProcessAfterInitialization 中完成 AOP 代理包装,最终得到功能完备的单例 Bean。关键边界:
populateBean() 不是 initializeBean() 内部步骤。@PreDestroy 和 DisposableBean.destroy() 容器不会调用,需要手动管理。
06六、写在最后
理解了这些源码,你不仅能在面试中对答如流,在面对项目中复杂的 Spring 循环依赖报错或 AOP 失效问题时,也能快速定位根源。
源码剖析到这里,关于 Spring 的扩展点其实还有个大招没讲:BeanPostProcessor 的自定义实现,以及它在中间件(比如缓存、监控)中的实战用法。















































































