Spring Bean 的生命周期
Spring Bean 的生命周期简单易懂。在一个 bean 实例被初始化时,需要执行一系列的初始化操作以达到可用的状态。同样的,当一个 bean 不在被调用时需要进行相关的析构操作,并从 bean 容器中移除。
Spring bean factory 负责管理在 spring 容器中被创建的 bean 的生命周期。Bean 的生命周期由两组回调(call back)方法组成。
- 初始化之后调用的回调方法。
- 销毁之前调用的回调方法。
Spring 框架提供了以下四种方式来管理 bean 的生命周期事件:
- InitializingBean 和 DisposableBean 回调接口
- 针对特殊行为的其他 Aware 接口
- Bean 配置文件中的 Custom init() 方法和 destroy() 方法
- @PostConstruct 和 @PreDestroy 注解方式
四种回调方式列齐了,但生命周期真正的考点是完整顺序:从实例化到销毁的十几步中,Aware、后处理器、初始化回调各自的插入点。本文给出一条可背可推的主线顺序,并讲清每类扩展点的用途与优先级。
主线顺序(单例 bean)
- 实例化:createBeanInstance——构造器/工厂方法创建裸对象(依赖注入之前)
- 属性填充:populateBean——@Autowired/@Value/refs 注入;循环依赖在此靠三级缓存解决
- Aware 回调:BeanNameAware → BeanClassLoaderAware → BeanFactoryAware →(后处理器补充的 EnvironmentAware/ApplicationContextAware 等)
- 初始化前:BeanPostProcessor.postProcessBeforeInitialization——@PostConstruct 在此被 CommonAnnotationBeanPostProcessor 执行
- 初始化:InitializingBean.afterPropertiesSet → 自定义 init-method(@Bean(initMethod=…) / xml init-method)
- 初始化后:BeanPostProcessor.postProcessAfterInitialization——AOP 代理在此生成(AbstractAutoProxyCreator)
- 就绪使用:放入单例池 singletonObjects
- 销毁:容器 close 时 @PreDestroy → DisposableBean.destroy → destroy-method
记忆锚点:注入在 Aware 前,@PostConstruct 在 afterPropertiesSet 前,代理在最后一步——三个”前/后”关系覆盖了绝大多数追问。
四类扩展点的定位与优先级
| 扩展点 | 触发点 | 典型用途 | 侵入性 |
|---|---|---|---|
| @PostConstruct/@PreDestroy | 初始化前后 | 资源预热/释放(JSR250 标准) | 低(注解) |
| InitializingBean/DisposableBean | 同上(注解之后) | 框架内部组件常用 | 中(耦合 Spring 接口) |
| init-method/destroy-method | 同上(接口之后) | XML/配置类指定已有方法 | 低 |
| Aware 族 | 属性填充后 | 获取容器设施(name/context/env) | 中 |
| BeanPostProcessor | 初始化前后全局 | AOP、代理、字段加工(容器级扩展) | 容器级 |
同一 bean 同时定义多种初始化回调时执行顺序:@PostConstruct → afterPropertiesSet → init-method(销毁逆序同构)。业务代码优先 @PostConstruct(标准注解、不耦合接口);框架/中间件才用接口级回调。
生命周期与 scope 的交互
- singleton:随容器启动创建(预实例化)、随容器关闭销毁,全周期一次
- prototype:每次 getBean 走 1-6 步,但容器不管理销毁——@PreDestroy 对 prototype 不触发,资源释放需调用方负责(这是 prototype 最大的坑)
- request/session:Web 作用域,随 Web 生命周期创建销毁,配合 scoped-proxy 注入单例
常见坑清单
- 在构造器里做重初始化:依赖还没注入(populate 在后),NPE 高发;重活放 @PostConstruct
- @PostConstruct 里调用本类被代理的方法期望事务生效:代理在第 6 步才生成,此时还是裸对象,自调用无增强
- 依赖”其他 bean 已就绪”:单例初始化顺序由依赖图决定,跨 bean 的启动后逻辑应监听 ContextRefreshedEvent 而非各自 @PostConstruct 猜顺序
- 销毁不执行:非正常关闭(kill -9)或 prototype——资源泄漏来源
一句话主线
Bean 生命周期 = 实例化 → 注入 → Aware → 初始化前(@PostConstruct)→ 初始化(接口/方法)→ 初始化后(AOP 代理)→ 使用 → 销毁(三档逆序);扩展点按”注解优先、接口次之、配置兜底”选用,scope 决定容器管不管销毁。顺序记住三个锚点,其余步骤皆可定位。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 非鱼小站!
评论
WalineDisqus











