第74篇:Bean生命周期(2026版)
📌系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第73篇:Spring IoC容器 |
➡️ 下一篇:第75篇:Spring AOP原理
🗺️ 本文阅读地图(3 分钟速览)
第73篇搞定了IoC容器的概念,本篇深入Bean生命周期。很多开发者用了多年Spring,只停留在
@Autowired注入Bean的表层,一旦遇到Bean初始化顺序异常、循环依赖报错、扩展点执行不符合预期等问题,就无从下手。搞懂Bean生命周期,就是搞懂了Spring IoC容器的核心灵魂:
Spring全家桶专题持续推进,拿下AOP!
《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!
| 模块 | 核心问题 | 一句话回答 |
|---|---|---|
| 生命周期是什么 | Bean从生到死经历什么? | 实例化 → 属性填充 → 初始化 → 使用 → 销毁 |
| 实例化 | Bean对象怎么创建的? | 容器通过反射调用构造函数创建Bean实例 |
| 属性填充 | 依赖怎么注入的? | 容器通过依赖注入为Bean设置属性值 |
| 初始化 | 初始化阶段做了哪些事? | Aware回调 → BeanPostProcessor前置 → 初始化方法 → BeanPostProcessor后置 |
| Aware接口 | Bean怎么感知容器? | 实现BeanNameAware、BeanFactoryAware等接口,容器自动回调 |
| BeanPostProcessor | 怎么在初始化前后插一脚? | 实现postProcessBeforeInitialization和postProcessAfterInitialization |
| 销毁 | Bean怎么被销毁? | 容器关闭时,执行@PreDestroy→DisposableBean.destroy()→ 自定义destroy-method |
| 面试最爱问 | 高频考点有哪些? | 见文末 面试小节 |
一、核心知识点
1. 什么是Bean生命周期?
Bean的生命周期指的是一个Bean从创建到销毁的完整过程。Spring IoC容器会按照固定的流程,完成Bean的实例化、属性注入、初始化、销毁全生命周期管控。
💡普通对象 vs Bean:普通Java对象通过
new关键字手动实例化,生命周期仅与JVM垃圾回收相关;Spring Bean由IoC容器统一管理,容器提供了大量可插拔的扩展点,允许开发者在生命周期的任意节点介入。普通对象的命运握在开发者手里,Bean的命运握在Spring容器手里。
2. 为什么需要了解Bean生命周期?
| 价值 | 说明 |
|---|---|
| 问题排查 | 遇到初始化异常、依赖注入问题时,能快速定位问题阶段 |
| 功能扩展 | 通过BeanPostProcessor等扩展点实现AOP、属性加密等高级功能 |
| 性能优化 | 了解各阶段执行时机,避免在初始化阶段执行耗时操作 |
| 架构设计 | 开发Spring生态中间件时,必须充分理解生命周期才能正确集成 |
3. 谁在管理Bean的生命周期?
Spring中负责管理Bean生命周期的核心类是AbstractAutowireCapableBeanFactory。它定义了创建Bean的模板方法——实例化、属性填充、初始化的顺序固定,但具体步骤可以被子类扩展。
二、通俗讲解(1分钟开心学)
把Bean的生命周期想象成"员工入职流程"
这个比喻来自网络上的经典总结,非常形象:
- ① 实例化:公司(Spring容器)根据简历(BeanDefinition)发出Offer,员工来报到——分配工位(分配内存),人进来了,但电脑、工牌都还没配。
- ② 属性填充:HR给员工配电脑、工牌、门禁卡——这就是依赖注入,把需要的"装备"(依赖的其他Bean)配齐。
- ③ Aware回调:员工认识一下公司环境——知道自己的工号(
BeanNameAware)、知道HR部门在哪(BeanFactoryAware)、知道公司在几号楼(ApplicationContextAware)。 - ④ BeanPostProcessor前置处理:入职体检——在正式上岗前做一次检查。
- ⑤ 初始化:参加新员工培训(
@PostConstruct)、签劳动合同(InitializingBean.afterPropertiesSet())、领工服(自定义init-method)。 - ⑥ BeanPostProcessor后置处理:发放工作证——AOP动态代理就是在这里创建的。
- ⑦ 使用:正式上岗干活。
- ⑧ 销毁:离职交接——还电脑(
@PreDestroy)、办离职手续(DisposableBean.destroy())、注销工号(自定义destroy-method)。
三、Bean生命周期完整流程(15步)
一个完整的Spring Bean生命周期可以分为四大阶段、15个关键步骤:
四、各阶段深度拆解
4.1 实例化阶段(Instantiation)
容器通过反射机制调用构造函数创建Bean的实例。这是生命周期的起点。
💡实例化 ≠ 初始化:实例化只是"把人招进来、工位分配好",但电脑、工牌都还没配。属性填充和初始化才是"配装备、做培训"。
4.2 属性填充阶段(Populate Properties)
容器通过依赖注入为Bean设置属性值。这是Spring IoC的核心能力——@Autowired、@Resource等注解的处理都在这个阶段完成。
4.3 初始化阶段(Initialization)
这是生命周期中最复杂的阶段,包含多个子步骤。执行顺序必须严格遵循:
| 顺序 | 步骤 | 说明 |
|---|---|---|
| ① | BeanNameAware.setBeanName() | 传递Bean的ID/名称 |
| ② | BeanFactoryAware.setBeanFactory() | 传递BeanFactory实例 |
| ③ | ApplicationContextAware.setApplicationContext() | 传递ApplicationContext实例 |
| ④ | BeanPostProcessor.postProcessBeforeInitialization() | 初始化前处理 |
| ⑤ | @PostConstruct | JSR-250标准注解方式 |
| ⑥ | InitializingBean.afterPropertiesSet() | 接口方式初始化 |
| ⑦ | 自定义init-method | XML或@Bean(initMethod="...")指定 |
| ⑧ | BeanPostProcessor.postProcessAfterInitialization() | 初始化后处理 |
💡关键点:
@PostConstruct→InitializingBean.afterPropertiesSet()→ 自定义init-method的执行顺序是固定的。AOP动态代理在BeanPostProcessor后置处理中创建——所以@Transactional、@Async等注解在此时生效。
4.4 Aware接口详解
Aware接口是一组感知接口,让Bean能够感知到Spring容器的基础设施。
| Aware接口 | 回调方法 | 作用 |
|---|---|---|
BeanNameAware | setBeanName(String name) | 获取Bean在容器中的名称 |
BeanFactoryAware | setBeanFactory(BeanFactory) | 获取BeanFactory实例 |
ApplicationContextAware | setApplicationContext(ApplicationContext) | 获取ApplicationContext实例 |
BeanClassLoaderAware | setBeanClassLoader(ClassLoader) | 获取类加载器 |
EnvironmentAware | setEnvironment(Environment) | 获取环境配置 |
4.5 BeanPostProcessor详解
BeanPostProcessor是Spring中最强大的扩展点之一。它允许开发者在Bean初始化前后插入自定义逻辑。
@ComponentpublicclassMyBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){// 初始化前执行——比如检查Bean是否满足某种条件System.out.println("Before initialization: "+beanName);returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){// 初始化后执行——AOP动态代理在此创建System.out.println("After initialization: "+beanName);returnbean;}}💡BeanPostProcessor不是Bean生命周期的一部分,但它是在Bean生命周期中起重要作用的组件。
4.6 销毁阶段(Destruction)
当容器关闭时,会按相反顺序触发销毁逻辑:
| 顺序 | 步骤 | 说明 |
|---|---|---|
| ① | @PreDestroy | JSR-250标准注解方式 |
| ② | DisposableBean.destroy() | 接口方式销毁 |
| ③ | 自定义destroy-method | XML或@Bean(destroyMethod="...")指定 |
五、代码验证
下面通过一个完整的示例来验证Bean生命周期的执行顺序:
// ========== 1. 自定义Bean ==========@ComponentpublicclassLifecycleBeanimplementsBeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean{publicLifecycleBean(){System.out.println("① 实例化:构造函数");}@AutowiredprivateSomeComponentsomeComponent;publicvoidsetSomeComponent(SomeComponentsomeComponent){System.out.println("② 属性填充:setSomeComponent");this.someComponent=someComponent;}@OverridepublicvoidsetBeanName(Stringname){System.out.println("③ Aware回调:BeanNameAware - "+name);}@OverridepublicvoidsetBeanFactory(BeanFactorybeanFactory){System.out.println("④ Aware回调:BeanFactoryAware");}@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext){System.out.println("⑤ Aware回调:ApplicationContextAware");}@PostConstructpublicvoidpostConstruct(){System.out.println("⑥ 初始化:@PostConstruct");}@OverridepublicvoidafterPropertiesSet(){System.out.println("⑦ 初始化:InitializingBean.afterPropertiesSet()");}@Bean(initMethod="customInit")publicclassMyConfig{// 自定义init-method}publicvoidcustomInit(){System.out.println("⑧ 初始化:自定义 init-method");}publicvoiddoWork(){System.out.println("⑨ 使用:业务方法被调用");}@PreDestroypublicvoidpreDestroy(){System.out.println("⑩ 销毁:@PreDestroy");}@Overridepublicvoiddestroy(){System.out.println("⑪ 销毁:DisposableBean.destroy()");}publicvoidcustomDestroy(){System.out.println("⑫ 销毁:自定义 destroy-method");}}// ========== 2. 自定义BeanPostProcessor ==========@ComponentpublicclassMyBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName){if(beaninstanceofLifecycleBean){System.out.println(" 🔹 BeanPostProcessor前置处理");}returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(beaninstanceofLifecycleBean){System.out.println(" 🔹 BeanPostProcessor后置处理(AOP代理在此创建)");}returnbean;}}// ========== 3. 启动容器 ==========@SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String[]args){ConfigurableApplicationContextcontext=SpringApplication.run(Application.class,args);LifecycleBeanbean=context.getBean(LifecycleBean.class);bean.doWork();context.close();// 触发销毁}}执行结果:
① 实例化:构造函数 ② 属性填充:setSomeComponent ③ Aware回调:BeanNameAware - lifecycleBean ④ Aware回调:BeanFactoryAware ⑤ Aware回调:ApplicationContextAware 🔹 BeanPostProcessor前置处理 ⑥ 初始化:@PostConstruct ⑦ 初始化:InitializingBean.afterPropertiesSet() ⑧ 初始化:自定义 init-method 🔹 BeanPostProcessor后置处理(AOP代理在此创建) ⑨ 使用:业务方法被调用 ⑩ 销毁:@PreDestroy ⑪ 销毁:DisposableBean.destroy() ⑫ 销毁:自定义 destroy-method六、避坑要点
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
混淆@PostConstruct和afterPropertiesSet()的执行顺序 | 依赖初始化顺序错误 | @PostConstruct先执行,afterPropertiesSet()后执行 |
| 在构造函数中调用未注入的属性 | 空指针异常 | 属性注入完成后才能在@PostConstruct中使用 |
| 认为AOP在Bean实例化时就生效 | @Transactional不生效 | AOP代理在BeanPostProcessor后置处理中创建 |
在BeanPostProcessor中创建新Bean | 破坏生命周期,可能导致循环依赖 | BeanPostProcessor只做增强处理,不创建新Bean |
忘记调用context.close() | 销毁方法不执行 | 在Spring Boot中无需手动处理,容器会自动关闭 |
七、面试高频考点
Q1:Spring Bean的生命周期有哪些阶段?
四个主要阶段:①实例化——容器通过反射调用构造函数创建实例;②属性填充——通过依赖注入设置属性值;③初始化——Aware回调 → BeanPostProcessor前置 →
@PostConstruct→InitializingBean.afterPropertiesSet()→ 自定义init-method→ BeanPostProcessor后置;④销毁——@PreDestroy→DisposableBean.destroy()→ 自定义destroy-method。
Q2:@PostConstruct、InitializingBean、init-method的执行顺序?
顺序是:
@PostConstruct→InitializingBean.afterPropertiesSet()→ 自定义init-method。@PostConstruct是JSR-250标准注解,优先级最高;InitializingBean是Spring接口方式;自定义init-method是XML或注解配置方式。
Q3:AOP代理是在生命周期的哪个阶段创建的?
AOP动态代理在
BeanPostProcessor.postProcessAfterInitialization()中创建。也就是说,在Bean完成初始化之后,Spring会检查这个Bean是否需要被代理(比如是否有@Transactional、@Async等注解),如果需要,就创建一个代理对象返回。
Q4:BeanPostProcessor和BeanFactoryPostProcessor的区别?
BeanFactoryPostProcessor是容器级别的扩展点,在所有Bean实例化之前执行,可以修改BeanDefinition(元数据)。BeanPostProcessor是Bean级别的扩展点,在Bean初始化前后执行,可以修改Bean实例本身。两者执行时机完全不同。
Q5:Aware接口的作用是什么?
Aware接口让Bean能够感知Spring容器的基础设施。比如
BeanNameAware让Bean知道自己的名字,ApplicationContextAware让Bean能拿到ApplicationContext实例。这样Bean就可以在初始化时主动获取容器中的资源。
面试官追问陷阱(加分题)
追问1:“BeanPostProcessor本身是一个Bean吗?它自己会走生命周期吗?”
👉会。
BeanPostProcessor本身也是由Spring容器管理的Bean,它自己也会经历完整的生命周期——实例化、属性填充、初始化。但有一个关键点:BeanPostProcessor的实例化会提前,在普通Bean实例化之前就完成,这样才能在普通Bean初始化时进行拦截处理。
追问2:“如果我在BeanPostProcessor.postProcessAfterInitialization()中返回了一个不同的对象(比如代理对象),会发生什么?”
👉 返回的对象会替换容器中原来的Bean实例。后续所有对这个Bean的依赖注入和
getBean()调用,拿到的都是这个新对象。这正是AOP的实现原理——Spring在postProcessAfterInitialization()中检查Bean是否需要切面增强,如果需要,就返回一个CGLIB或JDK动态代理对象,替换掉原始Bean。
追问3:“Bean的销毁方法在什么情况下不会被调用?”
👉 ①容器非正常关闭(如
kill -9强制杀死进程);②原型(prototype)作用域的Bean,容器不负责销毁;③单例Bean如果从未被使用(懒加载且没人调用),也不会触发销毁。
八、练习题
简答题:请按顺序说出Bean初始化的8个子步骤(从Aware回调到BeanPostProcessor后置处理)。
代码题:编写一个自定义
BeanPostProcessor,在Bean初始化前后打印日志,并验证执行顺序。分析题:某项目中
@Transactional注解不生效,经过排查发现AOP代理没有创建。请分析可能的原因,并给出解决方案。
📊 你的学习进度
- 当前:第74篇 / 共108篇 ·进阶篇:Spring全家桶(第73~82篇)
- ✅ 已完成:基础篇44篇 + 第45~74篇
- 📖 正在学:第74篇
- ⏳ 待学习:第75~108篇
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
👉 下一篇文章预告
🚀下一篇:《第75篇:Spring AOP原理》
内容简介:AOP核心概念(切面、通知、切入点)、JDK动态代理 vs CGLIB、
@Transactional底层原理、切面执行顺序、AOP失效场景。
👉Spring全家桶专题持续推进,拿下AOP!
📌《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!