如果这篇文章对你有帮助,欢迎关注我的CSDN账号「来福猿」, 有问题可以在评论区留言,我会一一回复。一、为什么要深入理解 Bean 生命周期
Spring 容器最核心的能力,就是帮我们管理对象的创建、依赖注入、初始化与销毁。很多开发者平常用@Component、@Autowired时并不会刻意关心背后发生了什么,但一旦接触到 AOP、事务、配置动态刷新、循环依赖或者资源泄漏排查,Bean 生命周期就会成为绕不过去的一道坎。
理解 Bean 生命周期至少有四个实际收益:第一,能看懂BeanPostProcessor为什么可以代理对象,从而理解 AOP 的实现基础;第二,能区分@PostConstruct、InitializingBean和自定义init-method的先后顺序,避免初始化逻辑写在错误的位置;第三,能正确释放数据库连接、线程池、文件句柄等资源,防止内存泄漏;第四,能在面试或源码阅读时,快速定位AbstractAutowireCapableBeanFactory中的关键方法。
本文以 Spring 5.x/6.x 的核心源码AbstractAutowireCapableBeanFactory为主线,把 Bean 生命周期拆成实例化、属性填充、初始化、销毁四个阶段,配合可运行的示例代码逐一分析。
二、Bean 生命周期全景流程
先建立整体印象。一个单例 Bean 从无到有、再到销毁,大致经过下面这条链路:
flowchart TD A[读取 BeanDefinition] --> B[createBeanInstance 实例化] B --> C[populateBean 属性填充] C --> D[initializeBean 初始化] D --> E[放入单例池 使用中] E --> F[容器关闭 close] F --> G[destroy 销毁回调]其中,initializeBean内部又隐藏了一条更细的顺序链,也是最容易被问到的部分:
flowchart TD A[initializeBean] --> B[invokeAwareMethods 回调 Aware 接口] B --> C[BeanPostProcessor before 前置处理] C --> D[InitializingBean.afterPropertiesSet] D --> E[自定义 init-method] E --> F[BeanPostProcessor after 后置处理] F --> G[Bean 就绪]下面我们沿着这条主线,逐个阶段看源码。
三、阶段一:Bean 实例化
3.1 createBeanInstance:创建 Bean 的入口
实例化解决的是「调用哪个构造方法或工厂方法把对象创建出来」的问题,这一步还没有做属性注入。核心代码在AbstractAutowireCapableBeanFactory#createBeanInstance中,其决策顺序可以概括为:
- 如果
BeanDefinition提供了Supplier,直接调用Supplier.get()创建实例; - 如果配置了工厂方法
factoryMethod,通过反射调用该静态或实例工厂方法创建; - 如果存在已解析的构造器缓存,直接使用缓存的构造器创建;
- 否则进入构造器推断
determineConstructorsFromBeanPostProcessors,交给SmartInstantiationAwareBeanPostProcessor选择合适的构造器; - 仍然无法推断时,回退到默认无参构造方法实例化。
源码主流程可简化为:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { Class<?> beanClass = resolveBeanClass(mbd, beanName); // 1. Supplier 优先 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // 2. 工厂方法 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // 3. 构造器推断 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, args); } // 4. 默认无参构造 return instantiateBean(beanName, mbd); }3.2 实例化前后插手的 PostProcessor
在真正调用构造方法前后,InstantiationAwareBeanPostProcessor提供了两个拦截点:
postProcessBeforeInstantiation:在实例化之前调用,如果返回值不为null,Spring 会直接使用这个返回值作为 Bean,跳过默认实例化流程,AOP 代理的提前创建就与此有关;postProcessAfterInstantiation:在实例化完成、属性填充之前调用,返回false可以阻止后续属性填充。
这一阶段只是「把对象造出来」,字段里的@Autowired依赖还没有被注入,下一阶段才处理依赖。
四、阶段二:属性填充
实例化得到的是一个「空壳」对象,接下来populateBean负责把配置文件、注解中的依赖值注入进去:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { // 1. 再次给 InstantiationAwareBeanPostProcessor 拦截机会 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } // 2. 按 AUTOWIRE_BY_NAME / AUTOWIRE_BY_TYPE 自动注入 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || AUTOWIRE_BY_TYPE) { autowireByName(...); autowireByType(...); } // 3. 处理 @Autowired、@Value、@Inject 等注解注入 for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); } // 4. 最终把属性值写入 Bean applyPropertyValues(beanName, mbd, bw, pvs); }这里有一个关键细节:@Autowired注解并不是由核心 BeanFactory 直接处理的,而是通过AutowiredAnnotationBeanPostProcessor这个InstantiationAwareBeanPostProcessor在postProcessProperties中完成注入。这也是为什么把@Autowired称为「后置处理器驱动的注入机制」。
五、阶段三:初始化
属性注入完成后,对象在业务上已经可以工作,但 Spring 还提供了一整套「初始化钩子」,让用户或框架有机会做进一步的定制。这条链路的入口是initializeBean,需要牢记其内部顺序。
5.1 第一步:Aware 接口回调
invokeAwareMethods会依次回调三个Aware接口:BeanNameAware、BeanClassLoaderAware和BeanFactoryAware。如果你的 Bean 实现了这些接口,就能拿到自身名称、类加载器和所属工厂的引用。除此之外的EnvironmentAware、ApplicationContextAware等则由ApplicationContextAwareProcessor等专门的处理器完成回调,原理类似。
5.2 第二步:BeanPostProcessor 前置处理
接下来遍历所有BeanPostProcessor,调用postProcessBeforeInitialization。@PostConstruct注解就是通过InitDestroyAnnotationBeanPostProcessor在此时执行的:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }5.3 第三步:InitializingBean.afterPropertiesSet
如果 Bean 实现了InitializingBean接口,invokeInitMethods会调用它的afterPropertiesSet()。紧接着,如果BeanDefinition上配置了自定义init-method(XML 中的init-method属性,或注解方式@Bean(initMethod = "...")),也会在此后通过反射执行。
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd) { // 1. InitializingBean 接口回调 if (bean instanceof InitializingBean) { ((InitializingBean) bean).afterPropertiesSet(); } // 2. 自定义 init-method String initMethodName = mbd.getInitMethodName(); if (initMethodName != null && !(bean instanceof InitializingBean && "afterPropertiesSet".equals(initMethodName))) { invokeCustomInitMethod(beanName, bean, mbd); } }5.4 第四步:BeanPostProcessor 后置处理
初始化方法执行完毕后,Spring 会再次遍历BeanPostProcessor,调用postProcessAfterInitialization。这是整个生命周期中「动手脚」最频繁的位置:AbstractAutoProxyCreator就在这里为 Bean 创建 AOP 代理。所以你最终通过getBean拿到的对象,很可能已经不是最初实例化的那个对象了。
把初始化阶段完整串起来,就是下面这张图:
flowchart LR A[Aware 回调] --> B[BeanPostProcessor before / PostConstruct] B --> C[afterPropertiesSet] C --> D[自定义 init-method] D --> E[BeanPostProcessor after / AOP 代理]六、后置处理器体系详解
理解了上面的流程,再看后置处理器家族会更清晰。它们虽然名字里都带 PostProcessor,但介入时机完全不同,容易混淆:
| 处理器类型 | 核心接口 | 介入时机 | 典型用途 |
|---|---|---|---|
| BeanFactoryPostProcessor | BeanFactoryPostProcessor | 容器启动阶段,Bean 实例化之前 | 修改 BeanDefinition、属性占位符替换、配置中心刷新 |
| BeanPostProcessor | BeanPostProcessor | 每个 Bean 初始化前后 | 日志、校验、AOP 代理创建 |
| InstantiationAwareBeanPostProcessor | InstantiationAwareBeanPostProcessor | 实例化前后、属性填充前后 | 替代默认构造、注解注入、循环依赖处理 |
| DestructionAwareBeanPostProcessor | DestructionAwareBeanPostProcessor | Bean 销毁之前 | 释放资源、清除缓存、@PreDestroy回调 |
一个容易背错的顺序是:BeanFactoryPostProcessor操作的是「Bean 的定义」,发生在任何 Bean 实例化之前;而BeanPostProcessor操作的是「Bean 的实例」,发生在每个 Bean 的初始化阶段。两者作用对象不同,不能混为一谈。
七、阶段四:销毁
7.1 destroy-method 的执行顺序
当容器调用close()关闭时,单例 Bean 会依次走销毁流程。其执行顺序与初始化基本对称:先执行@PreDestroy,再执行DisposableBean.destroy(),最后执行自定义destroy-method。
flowchart TD A[容器 close] --> B[DestructionAwareBeanPostProcessor before / PreDestroy] B --> C[DisposableBean.destroy] C --> D[自定义 destroy-method] D --> E[资源释放完成]7.2 registerDisposableBeanIfNecessary
Bean 是否在容器关闭时被销毁,取决于创建流程末尾的registerDisposableBeanIfNecessary。当 Bean 实现了DisposableBean、配置了destroy-method、或者被DestructionAwareBeanPostProcessor标记为需要销毁时,Spring 会将其封装成DisposableBeanAdapter并注册到容器的disposableBeans缓存中,关闭容器时统一回调。
八、源码主流程串讲:doCreateBean
把上面四个阶段合并起来,就得到了 Spring 创建 Bean 的「总导演」AbstractAutowireCapableBeanFactory#doCreateBean,核心逻辑如下:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) { // 1. 实例化:创建空的 Bean 实例 BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); Object bean = instanceWrapper.getWrappedInstance(); // 2. 属性填充:完成依赖注入 populateBean(beanName, mbd, instanceWrapper); // 3. 初始化:Aware 回调、before、init 方法、after Object exposedObject = initializeBean(beanName, bean, mbd); // 4. 注册销毁回调 registerDisposableBeanIfNecessary(beanName, bean, mbd); return exposedObject; }而initializeBean又把初始化阶段串了起来:
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) { // 1. Aware 接口回调 invokeAwareMethods(beanName, bean); // 2. 前置处理,@PostConstruct 在此执行 Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName); // 3. 初始化方法:afterPropertiesSet + 自定义 init-method invokeInitMethods(beanName, wrappedBean, mbd); // 4. 后置处理,AOP 代理在此创建 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); return wrappedBean; }记住这条调用链,面试中被问到「请描述 Spring Bean 的生命周期」时,基本就能把每个阶段和对应的源码方法一一对应起来了。
九、完整可运行示例
下面用一个注解方式启动的 Spring 应用,把整个生命周期按顺序打印出来,方便对照验证:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; public class BeanLifecycleDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println("==== 容器启动完成,开始使用 Bean ===="); UserService userService = context.getBean(UserService.class); userService.sayHello(); context.close(); System.out.println("==== 容器已关闭 ===="); } @Configuration static class AppConfig { @Bean(initMethod = "customInit", destroyMethod = "customDestroy") public UserService userService() { return new UserService(); } @Bean public MyBeanPostProcessor myBeanPostProcessor() { return new MyBeanPostProcessor(); } } static class UserService implements InitializingBean, DisposableBean { public UserService() { System.out.println("1. 构造方法:Bean 实例化"); } public void customInit() { System.out.println("4. 自定义 init-method:customInit()"); } @Override public void afterPropertiesSet() { System.out.println("3. InitializingBean.afterPropertiesSet()"); } public void sayHello() { System.out.println("业务方法:sayHello()"); } public void customDestroy() { System.out.println("7. 自定义 destroy-method:customDestroy()"); } @Override public void destroy() { System.out.println("6. DisposableBean.destroy()"); } } static class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof UserService) { System.out.println("2. BeanPostProcessor.postProcessBeforeInitialization()"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof UserService) { System.out.println("5. BeanPostProcessor.postProcessAfterInitialization()"); } return bean; } } }运行后控制台输出如下,顺序与前面的源码分析完全一致:
1. 构造方法:Bean 实例化 2. BeanPostProcessor.postProcessBeforeInitialization() 3. InitializingBean.afterPropertiesSet() 4. 自定义 init-method:customInit() 5. BeanPostProcessor.postProcessAfterInitialization() ==== 容器启动完成,开始使用 Bean ==== 业务方法:sayHello() 6. DisposableBean.destroy() 7. 自定义 destroy-method:customDestroy() ==== 容器已关闭 ====十、常见面试题与易错点
- 初始化顺序:构造方法 → 属性注入 →
@PostConstruct→afterPropertiesSet→ 自定义init-method,不要记反;@PostConstruct本质上是靠BeanPostProcessor的前置方法执行的。 - 拿到的 Bean 可能被替换:
postProcessAfterInitialization返回的对象会替换原对象,这也是 AOP 代理 Bean 的由来;如果处理器返回null,Spring 会保留原对象。 - BeanFactoryPostProcessor 与 BeanPostProcessor 的区别:前者改定义、在实例化前执行;后者改实例、在初始化前后执行。
- 为什么构造器注入能部分避免循环依赖:循环依赖的自动解围依赖「先实例化、再填充」的两段式创建,构造器注入在实例化阶段就要求依赖,因此无法靠三级缓存直接解围。
- 销毁方法不会自动处理所有资源:只有注册到
DisposableBeanAdapter的销毁逻辑才会在close()时执行;prototype作用域的 Bean 通常不由容器负责完整销毁,需要调用方自行管理。
十一、总结
Spring Bean 的生命周期可以概括为「两创建、两加工」:createBeanInstance完成实例化,populateBean完成依赖注入,initializeBean完成初始化回调与后置加工,最后在容器关闭时通过dispose链路完成销毁。整条链路的横切扩展能力都来自不同阶段的PostProcessor,这也是 Spring 框架高度可插拔的根本原因。
建议读者把AbstractAutowireCapableBeanFactory#doCreateBean作为阅读入口,配合本文的示例代码在本地断点调试一遍。把调用栈实际走一次,比单纯背诵顺序要可靠得多。