Spring Bean 生命周期的 7 步详解
Bean 生命周期是 Spring 面试和源码阅读中绕不开的核心话题。相比 5 步版本,7 步版本更完整,把 Aware 接口回调和销毁阶段也纳入进来,能更准确地描述 Bean 从创建到销毁的全过程。
一、7 步总览
① 实例化 → ② 属性赋值 → ③ Aware 回调 → ④ 初始化前 → ⑤ 初始化 → ⑥ 初始化后 → ⑦ 销毁
| 步骤 | 核心动作 | 对应扩展点 |
|---|---|---|
| 1. 实例化 | 调用构造方法创建对象 | InstantiationAwareBeanPostProcessor |
| 2. 属性赋值 | 依赖注入 | @Autowired、@Value |
| 3. Aware 回调 | 获取容器内部资源 | BeanNameAware、ApplicationContextAware 等 |
| 4. 初始化前 | 前置增强 | postProcessBeforeInitialization |
| 5. 初始化 | 执行自定义初始化方法 | @PostConstruct、InitializingBean、init-method |
| 6. 初始化后 | 后置增强,AOP 代理生成 | postProcessAfterInitialization |
| 7. 销毁 | 释放资源 | @PreDestroy、DisposableBean、destroy-method |
二、逐步拆解
第 1 步:实例化
Spring 通过反射调用构造方法创建 Bean 实例。如果使用构造器注入,依赖在这一步作为参数传入。如果使用字段注入,此时对象已创建,但字段还是 null。
@Service
public class UserService {
@Autowired
private UserDao userDao; // 此时为 null
public UserService() {
System.out.println("1. 实例化,userDao = " + userDao); // null
}
}
这一步的扩展点是 InstantiationAwareBeanPostProcessor,它可以在实例化前后介入,但日常开发中很少直接实现这个接口。AOP 的代理通常不在这一步生成,而是在第 6 步。
第 2 步:属性赋值
Spring 扫描 Bean 中标注了 @Autowired、@Value、@Resource 的字段和方法,从容器中查找匹配的依赖并注入。
@Autowired
private UserDao userDao; // 此时被注入
@Value("${app.name}")
private String appName; // 此时被注入
如果存在循环依赖,Spring 通过三级缓存提前暴露对象的早期引用。这也是为什么字段注入能解决循环依赖,而构造器注入不能——构造器注入在第 1 步就要求依赖就绪,字段注入在第 2 步才处理。
第 3 步:Aware 回调
如果 Bean 实现了 Aware 系列接口,Spring 会回调对应方法,把容器内部资源传进来。这一步让 Bean 能感知自己在容器中的“身份”和“环境”。
| Aware 接口 | 回调方法 | 获取的资源 |
|---|---|---|
BeanNameAware | setBeanName(String) | Bean 的名称 |
BeanFactoryAware | setBeanFactory(BeanFactory) | BeanFactory 实例 |
ApplicationContextAware | setApplicationContext(ApplicationContext) | ApplicationContext 实例 |
EnvironmentAware | setEnvironment(Environment) | Environment 实例 |
ResourceLoaderAware | setResourceLoader(ResourceLoader) | 资源加载器 |
ApplicationEventPublisherAware | setApplicationEventPublisher(...) | 事件发布器 |
@Component
public class MyBean implements BeanNameAware, ApplicationContextAware {
@Override
public void setBeanName(String name) {
System.out.println("3. Bean 名称: " + name);
}
@Override
public void setApplicationContext(ApplicationContext context) {
System.out.println("3. 获取到 ApplicationContext");
}
}
Aware 接口的调用顺序通常与接口在类中的声明顺序无关,而是由 AbstractAutowireCapableBeanFactory.invokeAwareMethods() 按固定顺序调用:BeanNameAware → BeanClassLoaderAware → BeanFactoryAware。ApplicationContextAware 等更高级的 Aware 接口由 ApplicationContextAwareProcessor 处理,在 BeanPostProcessor 的 postProcessBeforeInitialization 阶段调用。
第 4 步:初始化前
BeanPostProcessor 的 postProcessBeforeInitialization 方法被调用。这是 Spring 留给开发者的扩展点,可以在初始化方法执行之前做额外处理。
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("4. 初始化前: " + beanName);
return bean; // 返回 null 会中断后续流程
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("6. 初始化后: " + beanName);
return bean;
}
}
如果返回 null,Spring 不会继续执行后续的初始化流程,Bean 也不会被注册到容器中。
注意:ApplicationContextAware 等 Aware 接口的回调实际上也是在 ApplicationContextAwareProcessor 的 postProcessBeforeInitialization 中执行的,所以第 3 步和第 4 步在源码层面有重叠。为了便于理解,通常把 Aware 回调单独列为一步。
第 5 步:初始化
按固定顺序执行三种初始化方法:
@PostConstruct标注的方法InitializingBean.afterPropertiesSet()init-method或@Bean(initMethod = "...")
@Component
public class MyBean implements InitializingBean {
@PostConstruct
public void postConstruct() {
System.out.println("5.1 @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("5.2 afterPropertiesSet");
}
public void customInit() {
System.out.println("5.3 init-method");
}
}
执行顺序固定,不能调换。@PostConstruct 由 CommonAnnotationBeanPostProcessor 处理,afterPropertiesSet 由 InitializingBean 接口触发,init-method 由 AbstractAutowireCapableBeanFactory 调用。
这一步完成后,Bean 的依赖和初始化都已完成,可以安全使用注入的依赖。
第 6 步:初始化后
BeanPostProcessor 的 postProcessAfterInitialization 方法被调用。AOP 代理就是在这个阶段生成的。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// Spring 的 AbstractAutoProxyCreator 在这里创建代理
return bean;
}
如果 Bean 需要被 AOP 代理,容器中最终存放的是代理对象,而不是原始对象。这就是为什么同一个类内部方法调用不会触发 AOP——内部调用走的是原始对象,不是代理对象。
这一步完成后,Bean 被放入单例池(singletonObjects),可以被应用程序使用。
第 7 步:销毁
容器关闭时,Bean 的销毁流程按以下顺序执行:
@PreDestroy标注的方法DisposableBean.destroy()destroy-method或@Bean(destroyMethod = "...")
@Component
public class MyBean implements DisposableBean {
@PreDestroy
public void preDestroy() {
System.out.println("7.1 @PreDestroy");
}
@Override
public void destroy() {
System.out.println("7.2 destroy");
}
public void customDestroy() {
System.out.println("7.3 destroy-method");
}
}
执行顺序与初始化阶段对应:@PreDestroy → destroy() → destroy-method。
三、7 步完整示例
@Component
public class LifecycleBean implements BeanNameAware, InitializingBean, DisposableBean {
@Autowired
private UserDao userDao;
public LifecycleBean() {
System.out.println("1. 实例化:构造方法执行");
}
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware.setBeanName: " + name);
}
@PostConstruct
public void postConstruct() {
System.out.println("5.1 @PostConstruct 执行");
}
@Override
public void afterPropertiesSet() {
System.out.println("5.2 afterPropertiesSet 执行");
}
public void customInit() {
System.out.println("5.3 init-method 执行");
}
@PreDestroy
public void preDestroy() {
System.out.println("7.1 @PreDestroy 执行");
}
@Override
public void destroy() {
System.out.println("7.2 destroy 执行");
}
public void customDestroy() {
System.out.println("7.3 destroy-method 执行");
}
}
配置:
@Bean(initMethod = "customInit", destroyMethod = "customDestroy")
public LifecycleBean lifecycleBean() {
return new LifecycleBean();
}
输出:
1. 实例化:构造方法执行
2. 属性赋值:userDao 被注入
3. BeanNameAware.setBeanName: lifecycleBean
4. 初始化前:postProcessBeforeInitialization
5.1 @PostConstruct 执行
5.2 afterPropertiesSet 执行
5.3 init-method 执行
6. 初始化后:postProcessAfterInitialization
(Bean 就绪)
... 应用运行 ...
7.1 @PreDestroy 执行
7.2 destroy 执行
7.3 destroy-method 执行
四、5 步 vs 7 步
| 对比 | 5 步版本 | 7 步版本 |
|---|---|---|
| 步骤 | 实例化、属性赋值、初始化前、初始化、初始化后 | 多了 Aware 回调和销毁 |
| 适用场景 | 快速回答、日常面试 | 完整理解、源码阅读 |
| 核心差异 | 忽略 Aware 回调和销毁 | 覆盖 Bean 完整生命周期 |
5 步版本把 Aware 回调归入初始化前阶段,销毁阶段单独讨论。7 步版本把 Aware 回调和销毁都显式列出来,描述更完整。面试时可以先答 5 步,面试官追问再展开到 7 步。
五、作用域对生命周期的影响
| 作用域 | 生命周期 |
|---|---|
singleton | 容器启动时创建,容器关闭时销毁 |
prototype | 每次获取时创建,Spring 不管理销毁 |
request | 每次 HTTP 请求创建,请求结束时销毁 |
session | 每个会话创建,会话失效时销毁 |
application | 整个 ServletContext 生命周期 |
prototype 作用域的 Bean,第 7 步不会执行。Spring 只负责创建,不管理销毁。
六、常见追问
1. 为什么 @PostConstruct 能拿到注入的依赖?
因为它在第 5 步执行,而第 2 步已经完成了属性赋值。
2. AOP 代理在哪一步生成?
第 6 步,postProcessAfterInitialization。所以容器中存放的是代理对象。
3. 为什么内部方法调用不触发 AOP?
内部调用走的是原始对象,不是代理对象。代理对象只在容器中,外部调用才经过代理。
4. 构造方法中能用注入的依赖吗?
不能。第 1 步实例化时,第 2 步属性赋值还没开始。
5. Aware 回调在第几步?
第 3 步。BeanNameAware、BeanFactoryAware 等在 invokeAwareMethods() 中调用,ApplicationContextAware 等在第 4 步的 ApplicationContextAwareProcessor 中调用。为了便于理解,统一归为第 3 步。
七、总结
| 步骤 | 动作 | 关键扩展点 |
|---|---|---|
| 1. 实例化 | 反射调用构造方法 | InstantiationAwareBeanPostProcessor |
| 2. 属性赋值 | 依赖注入 | @Autowired、@Value |
| 3. Aware 回调 | 获取容器资源 | BeanNameAware、ApplicationContextAware |
| 4. 初始化前 | 前置增强 | postProcessBeforeInitialization |
| 5. 初始化 | 执行初始化方法 | @PostConstruct → afterPropertiesSet → init-method |
| 6. 初始化后 | 后置增强,AOP 代理生成 | postProcessAfterInitialization |
| 7. 销毁 | 释放资源 | @PreDestroy → destroy → destroy-method |
7 步版本比 5 步更完整,把 Aware 回调和销毁阶段都纳入进来。理解每一步的执行顺序和扩展点,就能解释 Spring 中大部分与 Bean 创建、代理、初始化、销毁相关的现象。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/weixin_51288065/article/details/166586426



