Bean生命周期
开篇:一个 Bean 从"出生"到"死亡"经历了什么?
一个人的一生可以概括为:出生 → 取名字 → 上学受教育 → 工作 → 退休 → 离世。Spring 中的 Bean 也有类似的一生:实例化 → 属性赋值 → 初始化 → 使用 → 销毁。
理解 Bean 的生命周期,不仅是面试高频考点,更是实际开发中排查问题的利器——你遇到的"Bean 注入为 null"、"初始化方法没执行"、"AOP 没生效"等问题,往往都跟生命周期的某个阶段有关。
需要注意:我们研究的是 Singleton Bean 的生命周期。对于 Prototype Bean,Spring 在用户
getBean()获得实例后就不再管理了,把管理权交给用户,此后再getBean()生成的是新实例。
一、生命周期四大阶段
Bean 的生命周期可以分为创建、使用、销毁三个大阶段,进一步细分为五个小阶段。核心流程如下:
这些阶段对应的核心源码都在 AbstractAutowireCapableBeanFactory 类的 doCreateBean() 方法中。这个方法就是 Bean 创建的"总控室":
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) {
// 1. 实例化:调用构造方法创建对象
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
// (这里会处理三级缓存,解决循环依赖)
// 2. 属性赋值:依赖注入
populateBean(beanName, mbd, instanceWrapper);
// 3. 初始化:各种回调和后置处理
exposedObject = initializeBean(beanName, exposedObject, mbd);
// 4. 注册销毁回调
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}有人把"属性赋值"和"初始化"合到一起叫"初始化",这容易混淆。在源码层面,
populateBean()(属性赋值)和initializeBean()(初始化)是两个独立的方法调用,阶段明确。
接下来逐一展开每个阶段。
二、实例化与属性填充
实例化(createBeanInstance)
实例化就是"把对象 new 出来"。这一步只做一件事:调用构造方法创建对象实例,分配内存空间。
Spring 的实例化逻辑如下:
- 解析 Bean 的类,确保类已被加载且是
public的 - 如果配置了工厂方法(
factory-method),通过工厂方法创建 - 否则,查找合适的构造函数:
- 有多个构造函数且需要自动装配参数 →
autowireConstructor() - 只有一个无参构造 →
instantiateBean()
- 有多个构造函数且需要自动装配参数 →
- 对于单例 Bean,Spring 会先检查缓存中是否已有实例,如果已存在直接复用
实例化完成后,你得到的是一个**"半成品"对象**——成员变量都是默认值(null、0、false),还没有注入任何依赖。就像是一个刚出生的婴儿,有了身体但还不会说话。
在实例化之后、属性赋值之前,如果这个 Bean 是单例的且允许循环引用,Spring 会把它的创建工厂放入三级缓存(
singletonFactories),这就是解决循环依赖的关键一步。详见循环依赖篇。
属性填充(populateBean)
属性填充就是"给成员变量赋值",也就是依赖注入真正发生的地方。
populateBean() 方法的主要流程:
- 调用
InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法,决定是否继续填充属性(返回false则跳过属性填充) - 根据自动装配模式(
byName/byType)查找并解析依赖的 Bean - 调用
InstantiationAwareBeanPostProcessor的postProcessProperties()方法——这就是@Autowired和@Resource注解处理的入口 - 执行依赖检查
- 调用
applyPropertyValues()把属性值设置到 Bean 实例中
属性填充完成后,Bean 的所有依赖都已就位。但还没有执行任何初始化回调。
三、初始化阶段的扩展点
初始化是生命周期中最丰富的阶段,Spring 提供了大量的扩展点。所有的初始化逻辑都在 initializeBean() 方法中编排:
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// 第一步:Aware 接口回调
invokeAwareMethods(beanName, bean);
// 第二步:BeanPostProcessor 前置处理(@PostConstruct 在这里执行)
Object wrappedBean = bean;
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 第三步:初始化方法(afterPropertiesSet + init-method)
invokeInitMethods(beanName, wrappedBean, mbd);
// 第四步:BeanPostProcessor 后置处理(AOP 代理在这里创建)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}执行顺序一目了然:
3.1 Aware 接口回调
如果 Bean 实现了某些 Aware 接口,Spring 会在这一步回调对应的方法,让 Bean 获取到容器的内部信息:
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
}
}常用的 Aware 接口:
| Aware 接口 | 回调方法 | 让 Bean 获取什么 |
|---|---|---|
BeanNameAware | setBeanName(String) | 当前 Bean 在容器中的名称 |
BeanClassLoaderAware | setBeanClassLoader(ClassLoader) | 加载当前 Bean 的类加载器 |
BeanFactoryAware | setBeanFactory(BeanFactory) | 当前 Bean 所在的 BeanFactory 引用 |
ApplicationContextAware | setApplicationContext(ApplicationContext) | 当前应用上下文(功能更丰富) |
这些接口提供了一种机制,使 Bean 可以与 Spring 框架的内部组件交互。比如前面 IoC 篇提到的 SpringContextHolder 就是通过 ApplicationContextAware 获取 ApplicationContext 的。
3.2 BeanPostProcessor 前置处理
BeanPostProcessor 是 Spring 最重要的扩展接口之一。它会在每个 Bean 的初始化前后被调用,是 Spring 内部实现各种注解处理和代理创建的核心机制。
前置处理的代码很简单——遍历所有 BeanPostProcessor,逐个调用 postProcessBeforeInitialization():
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
result = processor.postProcessBeforeInitialization(result, beanName);
if (result == null) return result;
}
return result;
}3.3 @PostConstruct 的执行原理
@PostConstruct 为什么会在 afterPropertiesSet() 之前执行?因为它是在 BeanPostProcessor 前置处理阶段被调用的,比 invokeInitMethods() 先一步。
具体链路:CommonAnnotationBeanPostProcessor 继承了 InitDestroyAnnotationBeanPostProcessor,在初始化时把 PostConstruct 注册为 initAnnotationType。当 postProcessBeforeInitialization() 执行时,它会扫描 Bean 中标注了 @PostConstruct 的方法并调用。
// CommonAnnotationBeanPostProcessor 构造方法中
public CommonAnnotationBeanPostProcessor() {
addInitAnnotationType(loadAnnotationType("jakarta.annotation.PostConstruct"));
addDestroyAnnotationType(loadAnnotationType("jakarta.annotation.PreDestroy"));
}3.4 InitializingBean 和自定义 init-method
在 invokeInitMethods() 方法中,Spring 按顺序做了两件事:
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd) {
// 先执行 afterPropertiesSet
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 再执行 init-method
String[] initMethodNames = mbd.getInitMethodNames();
if (initMethodNames != null) {
for (String initMethodName : initMethodNames) {
invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
}
}
}所以 afterPropertiesSet() 一定在 init-method 之前执行。
3.5 BeanPostProcessor 后置处理
后置处理方法 postProcessAfterInitialization() 在所有初始化回调执行完毕后调用。这一步最重要的事情是:AOP 代理在这里创建。
AbstractAutoProxyCreator(继承自 AnnotationAwareAspectJAutoProxyCreator)在 postProcessAfterInitialization() 中检查 Bean 是否有匹配的切面(Advisor),如果有,就创建代理对象:
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}wrapIfNecessary() 会查找所有匹配的 Advisor,如果存在,就调用 createProxy() 创建代理对象(JDK 或 CGLIB)。这就是为什么 AOP 代理是在 Bean 初始化的最后阶段才产生的。
完整的初始化回调执行顺序验证
用一个完整的例子来验证所有回调的执行顺序:
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
InitializingBean {
public LifecycleBean() {
System.out.println("1. 构造函数");
}
@Override
public void setBeanName(String name) {
System.out.println("2. BeanNameAware.setBeanName()");
}
@Override
public void setBeanFactory(BeanFactory factory) {
System.out.println("3. BeanFactoryAware.setBeanFactory()");
}
@PostConstruct
public void postConstruct() {
System.out.println("4. @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("5. afterPropertiesSet()");
}
public void customInit() {
System.out.println("6. init-method");
}
}
@Configuration
public class Config {
@Bean(initMethod = "customInit")
public LifecycleBean lifecycleBean() {
return new LifecycleBean();
}
}输出:
1. 构造函数
2. BeanNameAware.setBeanName()
3. BeanFactoryAware.setBeanFactory()
4. @PostConstruct
5. afterPropertiesSet()
6. init-method四、销毁阶段
当 Spring 容器关闭时(调用 context.close() 或 JVM 关闭钩子触发),会执行 Bean 的销毁逻辑。
需要注意:销毁回调的注册是在创建阶段的最后一步
registerDisposableBeanIfNecessary()完成的。注册时只是"登记"了销毁方法,真正执行是在容器关闭时。
三种销毁回调
销毁阶段有三种回调方式,执行顺序为:
public class ResourceBean implements DisposableBean {
private ExecutorService executor = Executors.newFixedThreadPool(4);
@PreDestroy
public void preDestroy() {
System.out.println("1. @PreDestroy - 准备关闭");
}
@Override
public void destroy() {
System.out.println("2. DisposableBean.destroy() - 关闭线程池");
executor.shutdown();
}
public void customDestroy() {
System.out.println("3. destroy-method - 最终清理");
}
}销毁的实际执行在 DisposableBeanAdapter.destroy() 方法中:
public void destroy() {
// 先执行 DisposableBean.destroy()
if (this.invokeDisposableBean) {
((DisposableBean) bean).destroy();
}
// 再执行自定义 destroy-method
if (this.destroyMethod != null) {
invokeCustomDestroyMethod(this.destroyMethod);
}
}@PreDestroy 则是在前面的 CommonAnnotationBeanPostProcessor 的 postProcessBeforeDestruction() 中执行的,和 @PostConstruct 的处理方式对称。
销毁回调的适用场景
| 回调方式 | 适用场景 |
|---|---|
@PreDestroy | 通用资源释放,最简洁 |
DisposableBean.destroy() | 框架级的清理逻辑(侵入性强,不推荐业务代码使用) |
destroy-method | 第三方库对象的清理(无法加注解的情况) |
注意:销毁方法只对单例 Bean 有效。Prototype Bean 的生命周期在
getBean()返回后就交给了用户,Spring 不负责销毁。
五、BeanPostProcessor 的妙用
BeanPostProcessor 是 Spring 扩展性的核心。它会应用到容器中每一个 Bean 的初始化过程,让你在 Bean "出厂"前做最后的检查和加工。
Spring 内部的重要实现
Spring 自己就大量使用了 BeanPostProcessor:
| 实现类 | 作用 |
|---|---|
CommonAnnotationBeanPostProcessor | 处理 @PostConstruct、@PreDestroy、@Resource 注解 |
AutowiredAnnotationBeanPostProcessor | 处理 @Autowired、@Value、@Inject 注解 |
AbstractAutoProxyCreator | 创建 AOP 代理对象 |
AnnotationAwareAspectJAutoProxyCreator | 处理 @Aspect 注解定义的切面 |
AsyncAnnotationBeanPostProcessor | 处理 @Async 注解 |
自定义 BeanPostProcessor
你也可以写自己的 BeanPostProcessor:
@Component
public class SensitiveFieldEncryptor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 检查 Bean 的字段上是否有 @Encrypted 注解
// 如果有,返回一个代理对象,在 getter 时自动解密
if (hasEncryptedFields(bean.getClass())) {
return createDecryptingProxy(bean);
}
return bean;
}
}BeanFactoryPostProcessor vs BeanPostProcessor
这两个接口名字很像,但作用阶段完全不同:
| 维度 | BeanFactoryPostProcessor | BeanPostProcessor |
|---|---|---|
| 作用时机 | Bean 实例化之前(修改 BeanDefinition) | Bean 初始化前后(修改 Bean 实例) |
| 作用对象 | BeanDefinition(Bean 的"图纸") | Bean 实例(已经 new 出来的对象) |
| 典型用途 | 修改属性值、替换占位符、动态注册 Bean | 修改 Bean、创建代理、注解处理 |
| 接口方法 | postProcessBeanFactory(ConfigurableListableBeanFactory) | postProcessBeforeInitialization / postProcessAfterInitialization |
打个比方:BeanFactoryPostProcessor 是在"图纸审核阶段"改设计稿,BeanPostProcessor 是在"产品出厂前"做质检和包装。
六、常见面试题精选
Q1:@PostConstruct、afterPropertiesSet、init-method 的执行顺序?
构造函数 → @PostConstruct → afterPropertiesSet → init-method。
原因:@PostConstruct 是在 BeanPostProcessor 的前置处理阶段执行的(由 CommonAnnotationBeanPostProcessor 把 PostConstruct 注册为 initAnnotationType,然后在 postProcessBeforeInitialization() 中扫描并调用)。而 afterPropertiesSet() 和 init-method 是在 invokeInitMethods() 方法中先后执行的,晚于前置处理。
Q2:Spring Bean 的完整生命周期是怎样的?
完整流程分为 11 个步骤:
- 实例化(
createBeanInstance):调用构造方法 - 属性赋值(
populateBean):依赖注入 - Aware 回调(
invokeAwareMethods):BeanNameAware、BeanFactoryAware 等 - BeanPostProcessor 前置处理(
applyBeanPostProcessorsBeforeInitialization) - @PostConstruct(在前置处理中,由 CommonAnnotationBeanPostProcessor 触发)
- afterPropertiesSet(
invokeInitMethods的第一步) - 自定义 init-method(
invokeInitMethods的第二步) - BeanPostProcessor 后置处理(
applyBeanPostProcessorsAfterInitialization):AOP 代理在此创建 - 注册销毁回调(
registerDisposableBeanIfNecessary) - Bean 就绪,处理业务
- 销毁(容器关闭时):@PreDestroy → DisposableBean.destroy() → destroy-method
创建阶段的代码在 AbstractAutowireCapableBeanFactory.doCreateBean() 中,销毁在 DisposableBeanAdapter.destroy() 中。
Q3:BeanPostProcessor 有什么用?
BeanPostProcessor 是 Spring 最重要的扩展点。它会在每个 Bean 的初始化前后被调用。Spring 内部用它来处理 @Autowired 注入(AutowiredAnnotationBeanPostProcessor)、@PostConstruct 回调(CommonAnnotationBeanPostProcessor)、AOP 代理创建(AbstractAutoProxyCreator)等核心功能。你也可以自定义 BeanPostProcessor 来实现自己的逻辑。
Q4:有什么情况会导致 Bean 无法初始化?
最常见的原因是循环依赖。虽然 Spring 用三级缓存解决了单例 setter 注入的循环依赖,但以下情况仍然会报错:
- 构造器注入的循环依赖(实例化阶段就需要依赖,无法提前暴露半成品对象)
- Prototype 作用域的循环依赖(每次创建新实例,无法缓存复用)
- SpringBoot 2.6+ 默认关闭了循环依赖支持(需要手动配置
spring.main.allow-circular-references=true或用@Lazy)
Q5:单例 Bean 和 Prototype Bean 的生命周期有什么区别?
单例 Bean 由 Spring 全程管理:创建、使用、销毁都在 Spring 的掌控中。Prototype Bean 则不同:Spring 只管创建和初始化,getBean() 返回实例后就"放手"了,后续的使用和销毁完全由用户负责。因此 Prototype Bean 的 @PreDestroy 和 DisposableBean.destroy() 不会被 Spring 自动调用。
小结
| 阶段 | 关键方法/接口 | 说明 |
|---|---|---|
| 实例化 | createBeanInstance() | 调用构造方法,创建"半成品"对象 |
| 属性填充 | populateBean() | 依赖注入,@Autowired 在这里处理 |
| Aware 回调 | invokeAwareMethods() | 让 Bean 感知容器内部信息 |
| 前置处理 | postProcessBeforeInitialization() | @PostConstruct 在这里执行 |
| 初始化方法 | invokeInitMethods() | afterPropertiesSet() → init-method |
| 后置处理 | postProcessAfterInitialization() | AOP 代理在这里创建 |
| 注册销毁回调 | registerDisposableBeanIfNecessary() | 登记 @PreDestroy / DisposableBean / destroy-method |
| 使用 | - | Bean 就绪,处理业务 |
| 销毁 | DisposableBeanAdapter.destroy() | @PreDestroy → destroy() → destroy-method |
Bean 的一生虽然看起来复杂,但逻辑线很清晰:先造出来(实例化),再装上零件(属性填充),然后做质检和包装(初始化各种回调 + AOP 代理),交付使用,最后报废回收(销毁)。 掌握了这条主线,再加上源码中 doCreateBean() 和 initializeBean() 两个核心方法的结构,你就能准确定位 Bean 在哪个阶段出了问题。