Bean的生命周期 高频考点!
一、Bean生命周期的核心阶段
Spring Bean的生命周期指的是一个Bean在IoC容器中从创建到销毁的完整过程。这个过程可以分为以下几个关键阶段:
- 实例化
- 容器通过反射调用Bean的构造函数创建对象实例
- 对应源码:
AbstractAutowireCapableBeanFactory.createBeanInstance()
- 属性赋值
- 容器为Bean注入所需的依赖(通过setter方法、字段注入或构造函数注入)
- 对应源码:
AbstractAutowireCapableBeanFactory.populateBean()
- Aware接口回调
- 如果Bean实现了各种Aware接口,容器会回调相应方法:
BeanNameAware.setBeanName()
:设置Bean的IDBeanFactoryAware.setBeanFactory()
:设置BeanFactory引用ApplicationContextAware.setApplicationContext()
:设置ApplicationContext引用
- 如果Bean实现了各种Aware接口,容器会回调相应方法:
- BeanPostProcessor前置处理
- 调用所有
BeanPostProcessor
的postProcessBeforeInitialization()
方法 - 这是对Bean进行增强的第一个扩展点
- 调用所有
- 初始化方法执行(Initialization)
- 三种方式的初始化方法按顺序执行:
@PostConstruct
注解标记的方法InitializingBean.afterPropertiesSet()
方法- XML或Java Config中自定义的
init-method
- 三种方式的初始化方法按顺序执行:
- BeanPostProcessor后置处理
- 调用所有
BeanPostProcessor
的postProcessAfterInitialization()
方法 - AOP代理正是在这个阶段通过
AbstractAutoProxyCreator
创建的
- 调用所有
- Bean就绪
- 此时Bean已经完全初始化,存在于应用上下文中,可以被其他对象使用
- 销毁
- 容器关闭时,执行销毁方法:
@PreDestroy
注解标记的方法DisposableBean.destroy()
方法- XML或Java Config中自定义的
destroy-method
- 容器关闭时,执行销毁方法:
二、常见面试问题深度剖析
1. Bean的实例化和初始化有什么区别?
这是考察对生命周期阶段划分的理解。实例化是指通过构造函数创建Bean对象的的过程,而初始化是指在对象创建完成后进行的属性注入和各种回调方法的执行。可以简单理解为:实例化是"出生",初始化是"成长"。
2. BeanPostProcessor和BeanFactoryPostProcessor有什么区别?
这个问题考察对Spring扩展机制的理解:
BeanFactoryPostProcessor
:在Bean定义加载完成后、Bean实例化之前执行,用于修改Bean的配置元数据。它是容器级别的操作。BeanPostProcessor
:在Bean实例化完成后、初始化前后执行,用于修改或包装Bean实例本身。它是Bean级别的操作。
3. 如何解决循环依赖问题?
Spring通过三级缓存机制解决setter注入的循环依赖:
- 一级缓存:存放完全初始化好的单例Bean
- 二级缓存:存放早期暴露的半成品Bean(已实例化但未初始化)•
三级缓存:存放ObjectFactory,用于生成早期引用
当发生循环依赖时,Spring会在Bean实例化后提前将其ObjectFactory放入三级缓存,这样在注入依赖时可以通过ObjectFactory.getObject()获取到早期引用,从而打破循环。
4. @PostConstruct和init-method的执行顺序是什么?
根据Spring官方文档,初始化方法的执行顺序是:
@PostConstruct
注解标记的方法InitializingBean.afterPropertiesSet()
方法- 自定义的
init-method
这种顺序设计确保了用户自定义的初始化方法具有最高的优先级。
5. Bean生命周期如何与AOP代理关联?
AOP代理的创建是在Bean生命周期的BeanPostProcessor
后处理阶段完成的。具体来说,AbstractAutoProxyCreator
会在其postProcessAfterInitialization()
方法中检查当前Bean是否需要被代理,如果需要则创建代理对象并返回,替代原有的Bean实例。
三、实际开发中的应用场景
- 性能优化:合理使用延迟初始化(@Lazy)避免应用启动时加载所有Bean
- 资源管理:在初始化方法中打开资源,在销毁方法中释放资源,避免内存泄漏
- 扩展定制:通过BeanPostProcessor实现自定义的逻辑增强,如日志记录、权限检查等
- 问题排查:当出现依赖注入失败或初始化异常时,能快速定位问题阶段