1. 生命周期全景图 (Mermaid)
以下流程图展示了 Spring Bean 从实例化到销毁的完整路径,以及关键扩展点的介入时机。
[开始]
|
v
1. 实例化 (Instantiation)
| <--- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
v
2. 属性填充 (Population)
| <--- InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
| <--- InstantiationAwareBeanPostProcessor.postProcessProperties (@Autowired)
v
3. Aware 接口回调
| (如果实现 BeanNameAware, ApplicationContextAware 等)
v
4. BeanPostProcessor.postProcessBeforeInitialization
|
v
5. 初始化 (Initialization)
| ---> @PostConstruct
| ---> InitializingBean.afterPropertiesSet()
| ---> 自定义 init-method
v
6. BeanPostProcessor.postProcessAfterInitialization
| *** AOP 代理对象通常在此阶段生成 ***
v
7. Bean 就绪 (Ready)
| (Bean 放入单例池,可供其他 Bean 依赖注入)
|
v
[容器关闭时触发销毁]
|
v
8. 销毁 (Destruction)
| ---> @PreDestroy
| ---> DisposableBean.destroy()
| ---> 自定义 destroy-method
v
[结束]
2. 核心阶段与扩展点映射
| 阶段 | 关键动作 | 核心扩展点/接口 | 典型应用场景 |
|---|---|---|---|
| 实例化 | 创建对象实例 | InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation | 返回代理对象以短路后续流程;AspectJ 集成 |
| 属性填充 | 依赖注入 (DI) | InstantiationAwareBeanPostProcessor.postProcessProperties | @Autowired, @Value 注解的处理逻辑 |
| Aware 回调 | 注入容器资源 | BeanNameAware, ApplicationContextAware 等 | 获取 Bean 名称、上下文环境、事件发布器等 |
| 初始化前 | 预处理 | BeanPostProcessor.postProcessBeforeInitialization | 检查注解、修改属性、动态代理准备 |
| 初始化 | 执行业务初始化 | @PostConstruct InitializingBean init-method | 数据库连接池初始化、缓存预热、参数校验 |
| 初始化后 | 后处理/AOP | BeanPostProcessor.postProcessAfterInitialization | AOP 代理对象创建、最终包装 |
| 销毁 | 资源清理 | @PreDestroy DisposableBean destroy-method | 关闭连接、释放线程池、保存状态 |
3. 容器级扩展点(在 Bean 实例化之前)
这些扩展点作用于容器层面,而非单个 Bean:
ApplicationContextInitializer: 容器刷新前调用。- 场景: 激活 Profile、设置 Context ID。
BeanDefinitionRegistryPostProcessor: BeanDefinition 加载后执行。- 场景: 动态注册 Bean(如 MyBatis Mapper 扫描、Feign Client 生成)。
BeanFactoryPostProcessor: Bean 实例化前修改元数据。- 场景: 解析占位符
${...}、加密属性解密。
- 场景: 解析占位符
4. 关键注意事项与陷阱
A. 循环依赖与三级缓存
- 机制: Spring 通过三级缓存解决单例、 setter/field 注入的循环依赖。
- 流程: 实例化后 -> 将
ObjectFactory放入三级缓存 -> 其他 Bean 获取早期引用 -> 完成属性填充。 - 局限: 构造器注入或 Prototype 作用域的循环依赖无法自动解决,需使用
@Lazy或重构代码。
B. 初始化方法执行顺序
严格遵循以下顺序,建议统一使用一种方式以避免混乱:
@PostConstruct(JSR-250 标准,推荐)InitializingBean.afterPropertiesSet()(Spring 接口,强耦合)- 自定义
init-method(配置指定)
C. AOP 代理的时机
- 关键点: AOP 代理通常在
postProcessAfterInitialization中生成。 - 陷阱: 在
@PostConstruct或afterPropertiesSet中调用当前 Bean 的方法,不会经过 AOP 切面(因为此时代理尚未完全接管或内部调用 bypass 代理)。事务注解在这些阶段无效。
D. 作用域差异
- Singleton: 容器管理完整生命周期(创建+销毁)。
- Prototype: 容器只负责创建和属性填充,不负责销毁。开发者需自行管理资源释放。
- Request/Session: 生命周期绑定 Web 请求或会话。
E. 性能优化
BeanPostProcessor会对容器中所有 Bean 执行。务必保持其逻辑轻量,避免在postProcessBefore/AfterInitialization中进行耗时操作(如远程调用、复杂计算),否则会显著增加应用启动时间。
5. 总结
Spring Bean 生命周期是一个高度可扩展的过程。理解扩展点的介入时机(特别是 BPP 的前后处理)、循环依赖的解决机制以及AOP 代理生成的滞后性,是掌握 Spring 核心原理的关键。在实际开发中,应优先使用注解(@PostConstruct/@PreDestroy)进行生命周期管理,并利用容器级扩展点处理框架集成需求。
评论区