Spring Bean 的生命周期是怎么样的?
结论先行:单例 Bean 的生命周期可以压成一条主线——实例化 → 属性填充 → Aware 回调 → 前置处理 → 初始化 → 后置处理(此处生成 AOP 代理)→ 使用 → 销毁。面试要能说清三个顺序:@PostConstruct 早于 afterPropertiesSet,早于自定义 init-method;BeanPostProcessor#postProcessAfterInitialization 是 AOP 代理诞生的地方;prototype Bean 容器不管销毁。
一、完整流程
① 读取 BeanDefinition(扫描/配置类解析)
│
② 实例化 instantiate ← 构造器、Supplier、FactoryBean#getObject
│
③ 属性填充 populateBean ← @Autowired / @Value 注入,依赖在此刻被拉取
│
④ Aware 回调 ← BeanNameAware → BeanClassLoaderAware → BeanFactoryAware
│
⑤ BeanPostProcessor.postProcessBeforeInitialization
│
⑥ 初始化
@PostConstruct
InitializingBean#afterPropertiesSet
自定义 init-method
│
⑦ BeanPostProcessor.postProcessAfterInitialization ← AOP 代理在此生成
│
⑧ 就绪,放入 singletonObjects,可被使用
│
⑨ 容器关闭:@PreDestroy → DisposableBean#destroy → destroy-method
二、扩展点归属
| 阶段 | 接口/注解 | 备注 |
|---|---|---|
| 实例化前 | InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation | 可返回代理,直接短路后续流程 |
| 属性填充前 | postProcessAfterInstantiation | 返回 false 可跳过注入 |
| 属性填充 | postProcessPropertyValues / @Autowired | 依赖注入发生点 |
| Aware | BeanNameAware、BeanFactoryAware、ApplicationContextAware | 让 Bean 拿到容器自身信息 |
| 初始化前 | postProcessBeforeInitialization | @PostConstruct 也在此阶段被调用 |
| 初始化 | InitializingBean、init-method | 顺序固定:注解 → 接口 → 配置 |
| 初始化后 | postProcessAfterInitialization | AOP 代理、@Async 代理生成 |
| 销毁 | @PreDestroy → DisposableBean → destroy-method | 仅单例由容器回调 |
三、代码验证顺序
@Component
public class LifecycleBean implements InitializingBean, DisposableBean, BeanNameAware {
public LifecycleBean() {
System.out.println("1 构造器");
}
@PostConstruct
public void postConstruct() {
System.out.println("3 @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("4 afterPropertiesSet");
}
public void initMethod() {
System.out.println("5 init-method");
}
@PreDestroy
public void preDestroy() {
System.out.println("7 @PreDestroy");
}
@Override
public void destroy() {
System.out.println("8 destroy");
}
@Override
public void setBeanName(String name) {
System.out.println("2 setBeanName(Aware)");
}
}
@Configuration
public class LifecycleConfig {
// 输出顺序:1 → 2 → 3 → 4 → 5 → (使用) → 7 → 8
@Bean(initMethod = "initMethod", destroyMethod = "destroy")
public LifecycleBean lifecycleBean() {
return new LifecycleBean();
}
}
四、AOP 代理的位置很关键
AbstractAutowireCapableBeanFactory#initializeBean 的末尾会调用 applyBeanPostProcessorsAfterInitialization,AnnotationAwareAspectJAutoProxyCreator 就在这里返回代理对象。所以:
- 初始化方法里
this仍指向原始对象,this.getClass()看不到代理; - 注入到其他 Bean 的是代理,因此事务、缓存、异步注解能生效;
@PostConstruct中调用本类的@Transactional方法不会走代理,事务不生效——这是"初始化里调事务方法失败"的根因。
五、常见追问
- 问:
BeanPostProcessor和BeanFactoryPostProcessor区别? 前者处理"Bean 实例",后者处理"BeanDefinition",且后者执行更早(refresh()的invokeBeanFactoryPostProcessors阶段)。 - 问:prototype Bean 会走销毁流程吗? 不会,容器不保存其引用,
@PreDestroy不触发,需自行释放。 - 问:循环依赖发生在哪一步? 属性填充(③)阶段:A 填充时发现依赖 B,B 填充时又发现依赖 A,靠三级缓存提前暴露引用解决。
- 问:
@PostConstruct在 JDK 11+ 找不到注解? 需引入jakarta.annotation-api;Spring Boot 3 已统一为jakarta.annotation.PostConstruct。
小结
背生命周期不要背十步名词,背"四段":造出来(实例化 + 填充 + Aware)、初始化(三个回调按序)、包一层(BPP 后置处理生成代理)、拆掉(销毁三个回调)。再把 AOP 代理位置和 prototype 不销毁两个细节补上,答案就有区分度了。