Spring Bean 完整生命周期
Spring Bean 完整生命周期
Bean 生命周期分四大阶段:实例化 → 填充属性(依赖注入) → 初始化 → 销毁配合扩展接口、注解、后置处理器完整流程,同时区分单例 Bean与多例 Bean差异。
前置说明
- 执行入口:
refresh()→finishBeanFactoryInitialization()实例化所有非懒加载单例 - 核心扩展点:
BeanPostProcessor(贯穿初始化前后,最重要后置处理器) - 多例 Bean:容器不管理销毁,仅执行到初始化阶段,容器关闭不会执行销毁方法
一、完整生命周期分步流程(单例 Bean)
阶段 1:Bean 实例化 Instantiate
Spring 根据 BeanDefinition 信息创建对象,两种方式:
- 无参构造反射
newInstance() - 工厂方法
factory-method
此时对象仅仅 new 出来,所有属性都是默认 null,依赖还未注入。
阶段 2:提前暴露工厂(解决循环依赖关键)
实例化完成后,立即将当前 Bean 的ObjectFactory存入三级缓存 singletonFactories。 作用:如果产生循环依赖,其他 Bean 可以提前拿到半成品对象(支持 AOP 代理)。
阶段 3:属性填充 PopulateBean(依赖注入)
给实例化后的对象填充属性、完成依赖注入,三种注入方式:
@Autowired/@Resource字段注入- set 方法注入
- 构造器注入(实例化阶段就完成,不走这里)
流程细节:
- 解析所有需要注入的依赖;
- 递归获取依赖 Bean(触发依赖 Bean 完整生命周期);
- 通过反射给当前 Bean 赋值;
循环依赖就是在这一步触发,依靠三级缓存拿到半成品完成注入。
阶段 4:执行 BeanPostProcessor 前置处理 postProcessBeforeInitialization
BeanPostProcessor 是全局后置处理器,对所有 Bean 生效
java
运行
Object postProcessBeforeInitialization(Object bean, String beanName)执行时机:属性填充完成,初始化方法执行之前典型场景:
@Value注解属性解析赋值;- AOP 代理创建(大部分代理在这里生成,循环依赖才会提前在三级缓存创建);
阶段 5:执行自定义初始化方法 Initialization
三层初始化逻辑,顺序固定:
1. 执行Aware系列接口(按固定顺序)
Aware 作用:让 Bean 获取 Spring 容器底层资源 执行顺序:
BeanNameAware:setBeanName (String name),获取当前 beanNameBeanFactoryAware:setBeanFactory (BeanFactory factory),获取 Bean 工厂ApplicationContextAware:setApplicationContext (ApplicationContext ctx),获取上下文
2. 执行@PostConstruct注解方法(JSR-250 标准)
Java 官方注解,写在自定义初始化方法上,优先级高于 xml 的 init-method。
java
运行
@PostConstruct public void init(){}3. 执行 InitializingBean 接口 afterPropertiesSet ()
Spring 内置接口,重写方法做初始化逻辑
java
运行
public void afterPropertiesSet() throws Exception;4. 执行 xml / 注解指定的自定义 init-method
xml 配置:<bean init-method="init"/>注解:@Bean(initMethod = "init")
阶段 6:执行 BeanPostProcessor 后置处理 postProcessAfterInitialization
java
运行
Object postProcessAfterInitialization(Object bean, String beanName)执行时机:所有初始化逻辑全部执行完毕后核心用途:
- AOP 正常 Bean 的动态代理生成(无循环依赖时在这里创建代理对象);
- 对 Bean 做包装、替换、自定义增强;
走完这一步,Bean 完全创建完成,存入一级缓存 singletonObjects,业务代码可以直接使用。
阶段 7:Bean 就绪,容器使用阶段
单例 Bean 常驻容器,每次获取直接从一级缓存返回; 多例 Bean 每次 getBean 都会完整走一遍实例化、属性填充、初始化流程。
阶段 8:容器关闭,销毁 Bean Destruction(仅单例 Bean 执行)
调用ctx.close()/registerShutdownHook()触发销毁流程,三层销毁逻辑,顺序固定:
1.@PreDestroy注解方法(JSR 标准,优先级最高)
java
运行
@PreDestroy public void destroy(){}2. DisposableBean 接口 destroy () 方法
Spring 内置销毁接口
java
运行
public void destroy() throws Exception;3. xml/@Bean 指定的 destroy-method
xml:<bean destroy-method="close"/>注解:@Bean(destroyMethod = "close")
多例 Bean:Spring 容器不缓存、不管理销毁,关闭容器不会执行任何销毁方法。
二、生命周期执行顺序极简总结(背诵版)
- 实例化对象(new)
- 存入三级缓存(解决循环依赖)
- 填充属性、依赖注入
- BeanPostProcessor before 初始化
- Aware 接口回调 → @PostConstruct → InitializingBean → init-method
- BeanPostProcessor after 初始化(AOP 代理生成)
- Bean 放入一级缓存,业务使用
- 容器关闭:@PreDestroy → DisposableBean → destroy-method
三、高频面试延伸问题
1. BeanPostProcessor 和 InitializingBean 的区别
BeanPostProcessor:全局处理器,所有 Bean 都会经过,分前后两个方法;AOP 核心依赖它;InitializingBean:单个 Bean 自身初始化接口,仅当前 Bean 执行,只有 afterPropertiesSet 一个方法。
2. @PostConstruct 和 InitializingBean、init-method 优先级
优先级从高到低:@PostConstruct>InitializingBean#afterPropertiesSet()> xml/@Bean init-method
3. 为什么多例 Bean 不会执行销毁方法?
多例 Bean 不会存入一级缓存,容器不持有多例 Bean 的引用,无法追踪对象,GC 由 JVM 管理,容器关闭无法主动调用销毁逻辑。
4. AOP 代理对象在生命周期哪个阶段创建?
两种情况:
- 无循环依赖:在
postProcessAfterInitialization(初始化之后)创建代理; - 存在循环依赖:提前从三级缓存 ObjectFactory 生成代理,存入二级缓存。
四、完整流程图文字版
plaintext
加载BeanDefinition ↓ 实例化Bean(反射new对象) ↓ 存入三级缓存 singletonFactories ↓ populateBean 属性填充、依赖注入 ↓ BeanPostProcessor.postProcessBeforeInitialization ↓ 执行Aware接口(BeanName→BeanFactory→ApplicationContext) ↓ 执行@PostConstruct方法 ↓ 执行InitializingBean.afterPropertiesSet() ↓ 执行自定义init-method ↓ BeanPostProcessor.postProcessAfterInitialization(创建AOP代理) ↓ 存入一级缓存 singletonObjects ,应用使用Bean ↓ 容器关闭 ↓ 执行@PreDestroy ↓ 执行DisposableBean.destroy() ↓ 执行自定义destroy-method