Spring Bean 的生命周期是怎么样的?
一则或许对你有用的小广告
欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书
《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于
Spring AI + Spring Boot 3.x + JDK 21...,查看介绍《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,查看介绍;演示链接:http://116.62.199.48:7070/《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/
新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍
截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观
面试考察点
-
流程掌握度:面试官不仅仅是想知道你能背出几个步骤,更是想看你能不能把 "实例化 → 属性注入 → 初始化 → 销毁" 这条主线讲清楚,而不是东一句西一句。
-
扩展点认知:是否了解
BeanPostProcessor、Aware接口、InitializingBean等关键扩展点,知道它们在生命周期中的执行顺序和实际用途。这才是区分 "背了八股文" 和 "真正用过 Spring" 的分水岭。 -
源码级理解:高级岗位可能会追问到
AbstractApplicationContext#refresh()和AbstractAutowireCapableBeanFactory#doCreateBean()的源码流程,看你是不是看过源码。
核心答案
一句话概括:实例化 → 属性注入 → Aware 回调 → BeanPostProcessor 前置处理 → 初始化 → BeanPostProcessor 后置处理 → 使用 → 销毁。
完整流程可以分为 4 个阶段、7 个核心步骤——
上图展示了 Bean 从生到死的完整旅程。下面分阶段拆解,每一步都不放过。
深度解析
一、实例化 — Bean 的 "出生"
Spring 通过反射调用类的构造函数,创建出一个对象实例。注意,这时候的对象还只是个 "半成品",属性都是 null,依赖一个都没注入。
// Spring 内部大致是这样做的
Class<?> clazz = Class.forName("com.example.UserService");
Object instance = clazz.getDeclaredConstructor().newInstance();
实例化的时机跟 Bean 的作用域有关:singleton Bean 在容器启动时(或首次被请求时)创建,prototype Bean 每次获取时创建。
二、属性注入 — 给 "半成品" 装配零件
实例化之后,Spring 开始给这个对象注入依赖和属性值,包括 @Autowired、@Value、@Resource 等注解标注的字段或方法,以及 XML 中配置的 property。
@Component
public class OrderService {
@Autowired
private UserService userService; // 这一步被注入
@Value("${order.timeout}")
private int timeout; // 这一步被注入
}
如果存在循环依赖(A 依赖 B,B 又依赖 A),Spring 通过三级缓存来解决 singleton 场景下的循环依赖。这个后面会单独出一篇讲,这里先不展开。
三、Aware 接口回调 — 让 Bean 知道 "自己在哪"
如果 Bean 实现了 Spring 提供的各种 Aware 接口,Spring 会在这个阶段把对应的资源注入进去。
@Component
public class MyBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware {
@Override
public void setBeanName(String name) {
// 拿到自己在容器中的名字
System.out.println("我的名字是:" + name);
}
@Override
public void setBeanFactory(BeanFactory factory) {
// 拿到 BeanFactory 引用
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
// 拿到 ApplicationContext 引用
}
}
常用的 Aware 接口:
| Aware 接口 | 注入的资源 |
|---|---|
BeanNameAware |
Bean 的名称 |
BeanFactoryAware |
BeanFactory 实例 |
ApplicationContextAware |
ApplicationContext 实例 |
EnvironmentAware |
Environment 实例 |
ResourceLoaderAware |
ResourceLoader 实例 |
说实话,日常开发中直接实现 Aware 接口的场景不多,但面试爱问。ApplicationContextAware 偶尔会用来在非 Spring 管理的类中获取 Bean。
四、BeanPostProcessor — 最强的扩展点
BeanPostProcessor 是 Spring 留给我们的最强大的扩展机制,AOP 代理、@PostConstruct 注解的处理、属性校验等都是通过它实现的。
public interface BeanPostProcessor {
// 初始化之前调用
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 初始化之后调用(AOP 代理通常在这步生成)
default Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
关键点:BeanPostProcessor 对容器中所有 Bean 都生效,不是一个 Bean 专属的。Spring 内置了很多 BeanPostProcessor,比如:
CommonAnnotationBeanPostProcessor:处理@PostConstruct和@PreDestroyAutowiredAnnotationBeanPostProcessor:处理@Autowired和@ValueAbstractAutoProxyCreator:处理 AOP 代理
没错,@PostConstruct 的执行时机是在 postProcessBeforeInitialization 阶段,由 InitDestroyAnnotationBeanPostProcessor 负责调用。很多人以为 @PostConstruct 是在 "初始化" 阶段执行,严格来说是初始化之前的 "前置处理" 阶段。
五、初始化 — Bean 的 "成人礼"
属性注入完成后,Bean 可以执行一些自定义的初始化逻辑。有三种方式,执行顺序如下:
@Component
public class MyBean implements InitializingBean {
// 第 1 个执行:@PostConstruct 注解方法
@PostConstruct
public void postConstruct() {
System.out.println("1. @PostConstruct 执行");
}
// 第 2 个执行:InitializingBean 接口方法
@Override
public void afterPropertiesSet() {
System.out.println("2. afterPropertiesSet() 执行");
}
// 第 3 个执行:自定义 init-method
public void customInit() {
System.out.println("3. 自定义 init-method 执行");
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "customInit")
public MyBean myBean() {
return new MyBean();
}
}
三种方式的执行顺序固定:@PostConstruct → afterPropertiesSet() → init-method。设计上给了你三个层次的选择,日常用 @PostConstruct 就够了。
六、销毁 — Bean 的 "善终"
容器关闭时(比如调用 ApplicationContext.close()),singleton Bean 会被销毁。销毁顺序和初始化顺序类似,也有三种方式:
@Component
public class MyBean implements DisposableBean {
// 第 1 个执行
@PreDestroy
public void preDestroy() {
System.out.println("1. @PreDestroy 执行");
}
// 第 2 个执行
@Override
public void destroy() {
System.out.println("2. DisposableBean#destroy() 执行");
}
// 第 3 个执行
public void customDestroy() {
System.out.println("3. 自定义 destroy-method 执行");
}
}
顺序同样是固定的:@PreDestroy → destroy() → destroy-method。
注意,prototype 作用域的 Bean,Spring 不会调用销毁回调。创建之后就撒手不管了,生命周期由你自己管理。这个坑不少人踩过。
七、完整代码验证
用一个完整的例子把所有步骤跑一遍:
@Component
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
public LifecycleBean() {
System.out.println("1. 构造函数:实例化");
}
@Autowired
public void setDependency(ApplicationContext ctx) {
System.out.println("2. 属性注入:@Autowired");
}
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware:beanName = " + name);
}
@Override
public void setBeanFactory(BeanFactory factory) {
System.out.println("4. BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext ctx) {
System.out.println("5. ApplicationContextAware");
}
@PostConstruct
public void postConstruct() {
System.out.println("6. @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("7. InitializingBean#afterPropertiesSet()");
}
@PreDestroy
public void preDestroy() {
System.out.println("8. @PreDestroy");
}
@Override
public void destroy() {
System.out.println("9. DisposableBean#destroy()");
}
}
面试高频追问
-
追问一:
BeanPostProcessor和BeanFactoryPostProcessor的区别?执行时机和作用对象完全不同。
BeanFactoryPostProcessor在 Bean 实例化之前 执行,操作的是BeanDefinition(Bean 的元数据),比如修改属性值、改变作用域。BeanPostProcessor在 Bean 实例化之后 执行,操作的是 Bean 实例本身。一个改图纸,一个改零件。 -
追问二:构造函数注入和
@Autowired字段注入,在生命周期中的执行顺序是什么?构造函数注入发生在实例化阶段(第 1 步),是最早执行的。
@Autowired字段注入发生在属性注入阶段(第 2 步)。所以构造函数里拿不到被@Autowired标注的字段值——因为还没注入呢。这也是为什么 Spring 官方推荐构造器注入,因为它能在对象创建时就保证依赖完整。 -
追问三:Bean 的创建和 AOP 代理的关系是什么?
AOP 代理通常在
BeanPostProcessor#postProcessAfterInitialization阶段生成。也就是说,Spring 先创建原始 Bean,走完前面的流程,最后再把它包装成代理对象。但如果 Bean 实现了SmartInstantiationAwareBeanPostProcessor(比如循环依赖场景),可能会提前创建代理,这涉及三级缓存的机制。
常见面试变体
- "描述一下 Spring Bean 从创建到销毁的完整过程"
- "
@PostConstruct和InitializingBean的执行顺序是什么?" - "
BeanPostProcessor在 Bean 生命周期中的作用是什么?" - "Spring 有哪些扩展点可以介入 Bean 的创建过程?"
记忆口诀
四大阶段:实例化 → 属性注入 → 初始化 → 销毁
初始化三件套:@PostConstruct → afterPropertiesSet() → init-method
销毁三件套:@PreDestroy → destroy() → destroy-method
一句话记:构造生,注入养,Aware 让它认识爹娘,前后置处理器给它打扮,初始化让它长大,用完了再销毁收场。
总结
Bean 生命周期看起来步骤多,但核心就是四件事:创建、注入、初始化、销毁。面试的时候先把这四个阶段说清楚,再补充 BeanPostProcessor 和 Aware 接口这些扩展点,基本满分。如果能说出 BeanPostProcessor 和 BeanFactoryPostProcessor 的区别,以及 AOP 代理在生命周期中的介入时机,面试官会觉得你是真正看过源码的。
