面试被问"Spring Bean 的生命周期",背了一堆名词(实例化、属性注入、初始化、销毁),但面试官追问"具体在哪个方法里触发的"就卡壳了。
完整流程
1. 实例化(Instantiation)
↓ 调用构造函数创建对象
2. 属性注入(Populate)
↓ @Autowired、@Value 注入依赖
3. Aware 接口回调
↓ BeanNameAware、BeanFactoryAware、ApplicationContextAware
4. BeanPostProcessor 前置处理
↓ postProcessBeforeInitialization()
5. 初始化(Initialization)
↓ @PostConstruct → InitializingBean.afterPropertiesSet() → init-method
6. BeanPostProcessor 后置处理
↓ postProcessAfterInitialization() ← AOP 代理在这里创建
7. 使用中
↓ Bean 在容器里被使用
8. 销毁(Destruction)
↓ @PreDestroy → DisposableBean.destroy() → destroy-method
用代码验证
@Component
public class MyBean implements InitializingBean, DisposableBean,
BeanNameAware, ApplicationContextAware {
public MyBean() {
System.out.println("1. 构造函数(实例化)");
}
@Value("${app.name:default}")
private String appName;
@Autowired
private SomeDependency dep;
// ↑ 2. 属性注入(在构造函数之后)
@Override
public void setBeanName(String name) {
System.out.println("3a. BeanNameAware: " + name);
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
System.out.println("3b. ApplicationContextAware");
}
@PostConstruct
public void postConstruct() {
System.out.println("5a. @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("5b. InitializingBean.afterPropertiesSet");
}
public void customInit() {
System.out.println("5c. init-method");
}
@PreDestroy
public void preDestroy() {
System.out.println("8a. @PreDestroy");
}
@Override
public void destroy() {
System.out.println("8b. DisposableBean.destroy");
}
public void customDestroy() {
System.out.println("8c. destroy-method");
}
}
启动后输出:
1. 构造函数(实例化)
3a. BeanNameAware: myBean
3b. ApplicationContextAware
5a. @PostConstruct
5b. InitializingBean.afterPropertiesSet
5c. init-method
关闭容器时:
8a. @PreDestroy
8b. DisposableBean.destroy
8c. destroy-method
实际开发中最常用的
大部分场景只需要关注三个注解:
@Component
public class CacheManager {
private Cache cache;
// 构造函数注入依赖
public CacheManager(RedisTemplate<String, String> redisTemplate) {
this.cache = new Cache(redisTemplate);
}
@PostConstruct // 初始化:Bean 创建完、属性注入完后执行
public void init() {
cache.warmUp(); // 预热缓存
System.out.println("缓存管理器初始化完成");
}
@PreDestroy // 销毁:容器关闭前执行
public void cleanup() {
cache.flush(); // 刷盘
System.out.println("缓存管理器已清理");
}
}
@PostConstruct 和 @PreDestroy 覆盖了 90% 的场景。
BeanPostProcessor — AOP 的秘密
@Component
public class TimingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String name) {
// 初始化之前处理
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String name) {
// 初始化之后处理
// AOP 代理就是在这里创建的!
if (bean.getClass().isAnnotationPresent(Timed.class)) {
return createProxy(bean); // 返回代理对象替换原对象
}
return bean;
}
}
postProcessAfterInitialization 可以返回一个代理对象替换原来的 Bean。Spring AOP 就是这么干的——在初始化后把原 Bean 包一层代理。
作用域对生命周期的影响
| Scope | 生命周期 |
|---|---|
| singleton(默认) | 容器启动时创建,容器关闭时销毁 |
| prototype | 每次注入时创建,容器不管销毁 |
| request | 每个 HTTP 请求创建一个 |
| session | 每个 Session 创建一个 |
prototype 的 Bean 容器不负责销毁——创建完就交给调用方了,需要自己清理。
总结
Bean 生命周期:构造函数 → 属性注入 → Aware 回调 → 前置处理 → 初始化(@PostConstruct → afterPropertiesSet → init-method)→ 后置处理(AOP 在这里)→ 使用 → 销毁(@PreDestroy → destroy → destroy-method)。实际开发中记住 @PostConstruct 和 @PreDestroy 就够了,面试的时候把完整流程说一遍。