1. Spring Bean生命周期全景图
在Spring框架中,Bean的生命周期管理是其核心功能之一。理解这个机制对于编写高效、稳定的Spring应用至关重要。一个典型的Spring Bean会经历以下完整生命周期阶段:
- 实例化(Instantiation)
- 属性赋值(Population)
- 初始化(Initialization)
- 使用(In Use)
- 销毁(Destruction)
每个阶段Spring都提供了扩展点,允许开发者介入控制。下面这张表格展示了完整生命周期阶段及其对应的回调接口:
| 生命周期阶段 | 回调接口/注解 | 触发时机 | 典型用途 |
|---|---|---|---|
| 实例化前 | BeanPostProcessor.postProcessBeforeInstantiation | 在构造函数调用前 | 替代默认实例化逻辑 |
| 实例化 | 构造函数 | 对象创建时 | 基础初始化 |
| 属性赋值前 | InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation | 属性注入前 | 修改属性注入行为 |
| 属性赋值 | @Autowired/@Value等 | 依赖注入阶段 | 设置依赖关系 |
| 初始化前 | BeanPostProcessor.postProcessBeforeInitialization | init-method前 | 前置处理 |
| 初始化 | @PostConstruct/InitializingBean | 初始化阶段 | 资源准备 |
| 初始化后 | BeanPostProcessor.postProcessAfterInitialization | init-method后 | 代理包装 |
| 销毁前 | - | 容器关闭时 | - |
| 销毁 | @PreDestroy/DisposableBean | Bean销毁时 | 资源释放 |
1.1 核心阶段详解
实例化阶段是生命周期的起点。Spring通过反射调用构造函数创建Bean实例。此时对象处于"半成品"状态,依赖尚未注入。
注意:构造函数中应避免调用其他Bean方法,因为依赖尚未就绪可能导致NPE
属性赋值阶段完成依赖注入。Spring会:
- 解析@Autowired/@Value等注解
- 处理setter方法注入
- 应用BeanPostProcessor的修改
初始化阶段是Bean可用的最后准备步骤。执行顺序为:
- @PostConstruct方法
- InitializingBean.afterPropertiesSet()
- XML中配置的init-method
2. 扩展点深度解析
2.1 BeanPostProcessor工作机制
BeanPostProcessor是Spring提供的最强大扩展接口。其工作流程如下:
java复制// 简化后的Spring处理逻辑
Object bean = createBeanInstance();
bean = applyBeanPostProcessorsBeforeInitialization(bean, name);
invokeInitMethods(bean);
bean = applyBeanPostProcessorsAfterInitialization(bean, name);
典型应用场景包括:
- AOP代理生成(AbstractAutoProxyCreator)
- @Autowired注解处理(AutowiredAnnotationBeanPostProcessor)
- 自定义注解解析
实战经验:BeanPostProcessor本身也是Bean,但会优先初始化。如果需要在其中依赖其他Bean,建议使用ObjectProvider延迟注入。
2.2 初始化方法的三种方式对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| @PostConstruct | 标准JSR-250,与容器解耦 | 需依赖javax.annotation-api | 推荐首选 |
| InitializingBean | 直接集成,调用时机最早 | 与Spring强耦合 | 框架内部使用 |
| init-method | XML配置灵活 | 类型不安全 | 遗留系统维护 |
实测执行顺序(可通过调试观察):
- @PostConstruct
- afterPropertiesSet()
- init-method
3. 销毁阶段的正确实践
3.1 销毁方法的执行保障
确保销毁方法被调用的关键配置:
xml复制<!-- web.xml中配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
或者使用现代Spring Boot方式:
java复制@Bean(destroyMethod = "cleanup")
public DataSource dataSource() {
// 数据源配置
}
3.2 资源释放模式
推荐采用防御式销毁模式:
java复制public class ResourceHolder implements DisposableBean {
private volatile boolean destroyed = false;
@Override
public void destroy() {
if(destroyed) return;
// 释放资源
destroyed = true;
}
public void doWork() {
if(destroyed) throw new IllegalStateException("Bean已销毁");
// 业务逻辑
}
}
4. 生命周期中的典型问题排查
4.1 循环依赖解决方案
Spring通过三级缓存解决setter注入的循环依赖:
- singletonFactories(三级缓存)
- earlySingletonObjects(二级缓存)
- singletonObjects(一级缓存)
构造器注入的循环依赖无法解决,常见报错:
code复制Requested bean is currently in creation: Is there an unresolvable circular reference?
解决方案:
- 改为setter注入
- 使用@Lazy延迟初始化
- 重构设计消除循环
4.2 初始化顺序控制
当多个Bean存在依赖时,可使用:
java复制@DependsOn({"dataSource", "transactionManager"})
@Service
public class OrderService {
//...
}
或在XML中配置:
xml复制<bean id="serviceA" class="x.y.ServiceA" depends-on="daoA,daoB"/>
5. 高级生命周期控制
5.1 SmartInitializingSingleton
在单例Bean初始化完成后触发的扩展点:
java复制public class MySmartInitializer implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
// 所有单例Bean初始化完成后执行
}
}
典型应用:
- 启动后检查
- 缓存预热
- 定时任务注册
5.2 Bean作用域与生命周期
不同作用域的Bean生命周期差异:
| 作用域 | 创建时机 | 销毁时机 | 适用场景 |
|---|---|---|---|
| singleton | 容器启动时 | 容器关闭时 | 无状态服务 |
| prototype | 每次请求时 | GC回收时 | 有状态对象 |
| request | HTTP请求时 | 请求结束时 | Web层组件 |
| session | 会话创建时 | 会话过期时 | 用户会话数据 |
对于prototype作用域的Bean,Spring不会管理其完整生命周期,需要自行处理资源释放。