结论先行
Spring Bean的生命周期由IoC容器管理,核心流程为“实例化 → 属性注入 → 初始化 → 使用 → 销毁”,通过扩展点(如BeanPostProcessor
)和标准接口(如InitializingBean
)实现精细控制。以下是完整内容:
文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读
一、核心流程图
1. 实例化 → 2. 属性注入 → 3. Aware回调 → 4. 初始化前处理 → 5. 初始化 → 6. 初始化后处理 → 7. 使用 → 8. 销毁前处理 → 9. 销毁
二、详细阶段说明
1. 实例化(Instantiation)
- 动作:通过反射调用构造函数或工厂方法创建Bean实例(此时对象属性未赋值)。
- 扩展点:
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
:- 作用:可返回自定义对象(如Mock对象),跳过Spring默认实例化。
2. 属性注入(Population)
- 动作:通过Setter、构造器或字段注入依赖(如
@Autowired
、@Value
)。 - 扩展点:
InstantiationAwareBeanPostProcessor.postProcessProperties()
:- 作用:动态修改注入的属性值(如解密敏感配置)。
3. Aware接口回调
- 动作:若Bean实现Aware接口,容器自动注入资源:
BeanNameAware
:设置Bean的名称。ApplicationContextAware
:注入ApplicationContext引用(可用于手动获取其他Bean)。
4. 初始化前处理(Before Initialization)
- 动作:
- 执行
@PostConstruct
注解的方法。 - 调用
BeanPostProcessor.postProcessBeforeInitialization()
。
- 执行
- 典型用途:数据预热、依赖校验。
5. 初始化(Initialization)
- 动作顺序:
- 调用
InitializingBean.afterPropertiesSet()
(Spring接口)。 - 执行自定义
init-method
(通过XML或@Bean(initMethod="...")
配置)。
- 调用
6. 初始化后处理(After Initialization)
- 动作:
- 调用
BeanPostProcessor.postProcessAfterInitialization()
。 - AOP代理生成:如
@Transactional
、@Async
在此阶段生效。
- 调用
7. 使用阶段(In Use)
- 注意:若Bean被AOP代理,业务代码实际调用的是代理对象。
8. 销毁前处理(Before Destruction)
- 动作:
- 执行
@PreDestroy
注解的方法。
- 执行
9. 销毁(Destruction)
- 动作顺序:
- 调用
DisposableBean.destroy()
(Spring接口)。 - 执行自定义
destroy-method
。
- 调用
三、关键扩展点总结
扩展点/接口 | 作用阶段 | 核心功能 |
---|---|---|
InstantiationAwareBeanPostProcessor | 实例化、属性注入 | 拦截实例化、动态修改属性值(如解密敏感字段) |
BeanPostProcessor | 初始化前后 | AOP代理生成、全局预处理(如日志埋点) |
Aware接口 | Aware回调阶段 | 获取容器资源(如Bean名称、ApplicationContext) |
@PostConstruct /@PreDestroy | 初始化前/销毁前 | 无侵入式初始化和清理(如缓存预热、资源释放) |
InitializingBean /DisposableBean | 初始化/销毁阶段 | Spring原生生命周期接口(强耦合,慎用) |
四、实战场景与代码示例
场景1:动态解密敏感配置
public class DecryptBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String name) {
// 解密带有@Encrypted注解的字段
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Encrypted.class)) {
field.setAccessible(true);
String value = (String) pvs.getPropertyValue(field.getName()).getValue();
field.set(bean, decrypt(value)); // 解密逻辑
}
}
return pvs;
}
}
场景2:AOP代理导致内部调用失效
- 问题:在Bean内部调用
this.method()
时,@Transactional
不生效。 - 原因:内部调用绕过代理对象,直接调用原始方法。
- 解决:通过
AopContext
获取代理对象:public void save() { ((UserService) AopContext.currentProxy()).update(); // 通过代理对象调用 }
场景3:资源释放
@Service
public class DataSourceService {
@PreDestroy
public void cleanup() {
dataSource.close(); // 关闭数据库连接池
}
}
五、常见问题解答
-
循环依赖如何解决?
- Setter注入:通过三级缓存(提前暴露半成品Bean)。
- 构造器注入:无法解决,直接报错。
-
为什么AOP代理在初始化后生成?
- 确保所有依赖注入完成,避免代理对象因属性未注入而失效。
-
销毁方法不执行怎么办?
- 检查点:确保Bean是单例作用域,且容器正常关闭(如调用
context.close()
)。
- 检查点:确保Bean是单例作用域,且容器正常关闭(如调用
总结
Spring Bean生命周期是IoC容器的核心机制,本质是“标准化流水线 + 扩展点开放”的设计。掌握以下两点即可应对大多数场景:
- 流程顺序:实例化 → 属性注入 → 初始化 → 代理生成 → 销毁。
- 扩展点选择:
- 干预实例化:
InstantiationAwareBeanPostProcessor
。 - 干预初始化:
BeanPostProcessor
。 - 资源管理:
@PostConstruct
/@PreDestroy
。
- 干预实例化: