当前位置: 首页 > news >正文

java面试必问11:Spring Bean 生命周期:从实例化到销毁,一篇讲透

Spring Bean 生命周期:从实例化到销毁,一篇讲透

面试官:“说一下 Spring Bean 的生命周期。”
你:“Bean 的生命周期包括:实例化、填充属性、初始化前(BeanPostProcessor)、初始化(afterPropertiesSet/init-method)、初始化后、正常使用、销毁。”
面试官:“那 Aware 接口是在哪个阶段调用的?BeanPostProcessor 和 InitializingBean 的执行顺序是怎样的?”
你:“……”

很多人能背出主要阶段,但一追问细节就乱了。本文从源码角度,把 Bean 从创建到销毁的完整流程讲清楚,并附上代码示例和常见面试追问。


一、Bean 生命周期总览

Spring 容器管理 Bean 的完整生命周期可以分为三大阶段:创建(实例化 → 属性填充 → 初始化)→ 使用 → 销毁。其中初始化前后还穿插着各种 Aware 接口和 BeanPostProcessor 扩展点。

完整流程(按时间顺序):

1. 实例化(构造器/工厂方法) 2. 属性赋值(依赖注入) 3. BeanNameAware.setBeanName() 4. BeanClassLoaderAware.setBeanClassLoader() 5. BeanFactoryAware.setBeanFactory() 6. ApplicationContextAware.setApplicationContext()(若容器是 ApplicationContext) 7. BeanPostProcessor.postProcessBeforeInitialization() 8. InitializingBean.afterPropertiesSet() 9. 自定义 init-method 10. BeanPostProcessor.postProcessAfterInitialization() 11. 使用 Bean 12. DisposableBean.destroy() 13. 自定义 destroy-method

下图直观展示了各阶段顺序:

实例化 → 属性填充 → Aware接口 → 前置处理 → 初始化 → 后置处理 → 使用 → 销毁

二、各阶段详解

1. 实例化(Instantiation)

容器通过构造器工厂方法创建 Bean 的实例。此时 Bean 对象已经存在,但属性尚未赋值(均为默认值或 null)。

  • 默认使用无参构造器,如果类没有无参构造器且未指定构造参数,Spring 会抛出异常。
  • 可以通过@Autowired标注有参构造器,或使用factory-method

2. 填充属性(Populate Properties)

Spring 根据配置(XML 中的<property>、注解@Value@Autowired等)为 Bean 的属性赋值。依赖注入发生在这个阶段。

  • 如果存在循环依赖,Spring 会提前暴露半成品对象(通过三级缓存解决)。
  • 属性赋值完成后,Bean 的状态基本完整(但可能尚未完成全部初始化)。

3. Aware 接口回调

如果 Bean 实现了某个 Aware 接口,Spring 会注入对应的资源。执行顺序固定:

Aware 接口注入的资源
BeanNameAwareBean 在容器中的名称(id/name)
BeanClassLoaderAware加载 Bean 的 ClassLoader
BeanFactoryAware当前的BeanFactory实例
ApplicationContextAware当前的ApplicationContext实例(仅在 ApplicationContext 容器中生效)

注意ApplicationContextAwareBeanFactoryAware之后调用,且要求容器是ApplicationContext类型(若为BeanFactory则不会调用)。

4. BeanPostProcessor 前置处理

BeanPostProcessor接口提供了两个方法:postProcessBeforeInitializationpostProcessAfterInitialization。在初始化方法执行前,Spring 会调用所有注册的BeanPostProcessorpostProcessBeforeInitialization方法。

典型用途:修改 Bean 的属性、生成代理对象、执行自定义检查等。Spring 内部很多功能(如@Autowired解析、AOP 代理创建)都是通过BeanPostProcessor实现的。

5. 初始化(Initialization)

初始化阶段包括两部分:

  • InitializingBean.afterPropertiesSet():如果 Bean 实现了该接口,Spring 会调用此方法。
  • 自定义 init-method:可以通过@Bean(initMethod = "init")或 XML 中的init-method指定一个无参方法,在 afterPropertiesSet 之后执行。

执行顺序afterPropertiesSet()先执行,然后执行自定义 init-method。

6. BeanPostProcessor 后置处理

初始化完成后,Spring 调用所有BeanPostProcessorpostProcessAfterInitialization方法。此时 Bean 已经完全准备好,可以返回给调用方。

AOP 代理的创建通常发生在这个阶段:AbstractAutoProxyCreatorBeanPostProcessor的实现,在postProcessAfterInitialization中判断是否需要为 Bean 生成代理对象。

7. Bean 使用

Bean 已经存在于容器中,可以供其他组件@Autowired或通过getBean()获取,执行业务逻辑。

8. 销毁(Destruction)

当容器关闭时(如ApplicationContext.close()),会销毁所有单例 Bean。销毁阶段包括:

  • DisposableBean.destroy():如果 Bean 实现了该接口,Spring 会调用此方法。
  • 自定义 destroy-method:通过@Bean(destroyMethod = "cleanup")或 XML 中的destroy-method指定,在 DisposableBean 的 destroy 之后执行。

作用域影响:上述生命周期描述适用于单例作用域(singleton)。对于原型作用域(prototype),Spring 只负责创建和初始化,不管理销毁,需要用户自行处理。


三、代码示例:完整演示生命周期

@ComponentpublicclassLifecycleBeanimplementsBeanNameAware,BeanFactoryAware,ApplicationContextAware,InitializingBean,DisposableBean{privateStringname;publicLifecycleBean(){System.out.println("1. 实例化:构造器");}@AutowiredpublicvoidsetName(@Value("testBean")Stringname){this.name=name;System.out.println("2. 属性填充:setName("+name+")");}@OverridepublicvoidsetBeanName(Stringname){System.out.println("3. BeanNameAware: "+name);}@OverridepublicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{System.out.println("4. BeanFactoryAware");}@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{System.out.println("5. ApplicationContextAware");}@OverridepublicvoidafterPropertiesSet()throwsException{System.out.println("7. InitializingBean.afterPropertiesSet()");}@PostConstruct// JSR-250,等价于 init-method 但更常用publicvoidpostConstruct(){System.out.println("6. @PostConstruct (在 afterPropertiesSet 之前?注意顺序)");// 实际执行顺序:@PostConstruct 在 afterPropertiesSet 之前,但早于自定义 init-method// 为清晰,这里单独标注顺序,实际需看注解处理器优先级。}@Bean(initMethod="customInit")// 配置类中指定publicvoidcustomInit(){System.out.println("8. 自定义 init-method");}@Overridepublicvoiddestroy()throwsException{System.out.println("9. DisposableBean.destroy()");}@PreDestroypublicvoidpreDestroy(){System.out.println("10. @PreDestroy (在 destroy 之前)");}publicvoidcustomDestroy(){System.out.println("11. 自定义 destroy-method");}}

注意:@PostConstruct@PreDestroy是 JSR-250 标准,Spring 支持,执行时机分别在afterPropertiesSet之前和destroy之前。


四、BeanPostProcessor 的使用示例

@ComponentpublicclassCustomBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{if(beaninstanceofLifecycleBean){System.out.println("BeanPostProcessor.before: "+beanName);}returnbean;}@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{if(beaninstanceofLifecycleBean){System.out.println("BeanPostProcessor.after: "+beanName);}returnbean;}}

执行顺序输出(简化):

1. 实例化 2. 属性填充 3. BeanNameAware 4. BeanFactoryAware 5. ApplicationContextAware BeanPostProcessor.before 6. @PostConstruct 7. afterPropertiesSet 8. 自定义 init-method BeanPostProcessor.after ... 使用 ... BeanPostProcessor.before // 原型Bean每次创建都会经过

五、常见面试追问

Q1:BeanPostProcessorInitializingBean的区别?

  • InitializingBeanBean 自身的初始化回调,只针对当前 Bean。
  • BeanPostProcessor容器级的扩展点,对所有 Bean 生效,可以在初始化前后进行统一增强(如代理、属性修改)。

Q2:AOP 代理在哪个阶段创建?

BeanPostProcessor.postProcessAfterInitialization阶段,具体是AbstractAutoProxyCreator类的实现。因此,如果 Bean 需要被代理,最终返回的是代理对象而非原始对象。

Q3:@PostConstruct@PreDestroyafterPropertiesSetdestroy的先后顺序?

  • @PostConstructafterPropertiesSet之前执行(因为CommonAnnotationBeanPostProcessor处理 JSR-250 注解的优先级高于InitializingBean)。
  • @PreDestroydestroy之前执行。

Q4:原型 Bean 的生命周期有什么不同?

  • 原型 Bean 在每次请求时都会创建新实例,执行实例化 → 属性填充 → 初始化(包括 Aware、PostConstruct、InitializingBean 等),但不会执行销毁阶段(容器不管理原型 Bean 的销毁)。用户需要自行处理资源释放。

Q5:FactoryBeanBeanFactory有什么区别?

  • BeanFactory是 Spring 容器的顶级接口,负责管理 Bean。
  • FactoryBean是一个特殊的 Bean,用于生成复杂对象。当通过&前缀获取时返回 FactoryBean 本身,否则返回其getObject()创建的对象。FactoryBean 的生命周期与普通 Bean 类似,但它的getObject()中创建的对象不由 Spring 管理生命周期(除非声明为 prototype)。

六、生命周期扩展点总结

扩展点时机用途
BeanPostProcessor初始化前后全局增强,如代理、属性注入
InstantiationAwareBeanPostProcessor实例化前后、属性填充前后控制实例化、属性赋值
BeanFactoryAware属性填充后,初始化前获取容器引用
InitializingBean自定义初始化前执行特定初始化逻辑
DisposableBean销毁时执行资源清理
@PostConstruct/@PreDestroy同 InitializingBean / DisposableBean注解方式更简洁
ApplicationListener容器事件发布时监听容器启动、关闭等事件

七、总结

阶段关键动作
实例化调用构造器 / 工厂方法
属性填充依赖注入
Aware 回调注入 BeanName、BeanFactory、ApplicationContext
前置处理BeanPostProcessor.postProcessBeforeInitialization
初始化@PostConstruct → afterPropertiesSet → init-method
后置处理BeanPostProcessor.postProcessAfterInitialization
使用业务调用
销毁@PreDestroy → destroy → destroy-method

一句话记住生命周期构造填充属 Aware,前置初始化后置跑;用完销毁两步走,PreDestroy 和 destroy

理解 Bean 生命周期不仅能让你在面试中对答如流,还能帮助你写出更优雅的扩展组件(如自定义BeanPostProcessor)。希望这篇文章能帮你彻底掌握 Spring Bean 的生命周期,欢迎继续讨论。

http://www.jsqmd.com/news/651455/

相关文章:

  • 终极指南:如何使用Universal x86 Tuning Utility彻底解决笔记本高温降频问题
  • CurXecute漏洞:AI代码编辑器Cursor的远程代码执行风险
  • 避开这些坑!网易云音乐开源API使用中的5个常见问题及解决方案
  • 睿港国际移民获瓦努阿图官方全方位授权,DSP护照与绿卡授权实力再获认可 - 资讯焦点
  • 写论文这件事,本质上是把“思维碎片”变成“知识成品”的过程。有的人工具顺、效率高
  • 用Cooledit Pro给全志T113-S3音频调试当‘耳朵’:手把手教你量化解决录音尖锐失真
  • 革命性抖音直播数据采集架构:10倍效率提升的实时分析引擎
  • 东方博宜OJ 2391:子串位置 ← KMP算法
  • 如何在3分钟内开始使用 YahooFinanceApi:免费获取全球金融数据的终极指南
  • JDBC操作事务
  • 3分钟快速上手:CardEditor卡牌批量生成器终极使用指南
  • LD3320语音识别芯片:从硬件架构到智能交互的全面解析
  • 计算机毕业设计:Python农业与气候数据可视化分析系统 Django框架 数据分析 可视化 爬虫 机器学习 大数据 深度学习(建议收藏)✅
  • 如何完整备份QQ空间:终极免费工具使用指南
  • Android开发者必看:VLC播放器options参数全解析(附实战代码)
  • DLSS Swapper:智能管理NVIDIA显卡DLSS文件的完整解决方案
  • 开源实践 | 基于深度盲超分的高光谱图像复原:从理论到代码实现
  • 避开VS2022的坑!Win10/11下用VS2019+CMake编译GTSAM 4.0.3 MATLAB工具箱全记录
  • 高采样率为何反而引入更多噪声?深入解析ADC采样中的噪声机制
  • 终极指南:TES5Edit零代码掌握上古卷轴5模组制作
  • 给 AI 装“技能”:Agent Skills 完全指南
  • 一键全选:OneMore插件如何让表格操作效率飙升300%
  • 如何用TwinCAT3制作加密库文件?保护你的PLC代码不被查看
  • YOLOV5训练中断恢复与轮数扩展的实战技巧
  • C/C++调试实战:如何用backtrace_symbols快速定位段错误(附完整代码)
  • 思科ISE紧急安全警报:两个CVSS 10.0级RCE漏洞可实现未授权远程完全接管
  • 4x4矩阵键盘的两种扫描方式对比:行列式vs线翻式(附STM32移植指南)
  • 国产优选:耐达讯自动化EtherCAT转RS232在工业协议转换中的卓越表现
  • Zemax公差分析实战:从‘过定位’到‘可制造性’,一个连续变焦红外镜头的优化避坑指南
  • 网络视听用户达 10.99 亿 微短剧成出海主力