Spring Bean 生命周期 ⭐⭐⭐⭐⭐
面试频率:★★★★★
工作频率:★★★★☆
⚡30 秒速记(复习只看这里)
🟢 一句话
Spring Bean 生命周期就是一个 Bean 从创建、依赖注入、初始化、使用到最终销毁的整个过程。
核心流程:
实例化
↓
属性填充 / 依赖注入
↓
Aware 回调
↓
BeanPostProcessor 前置处理
↓
初始化
↓
BeanPostProcessor 后置处理
↓
Bean 创建完成
↓
正常使用
↓
销毁
🟡 最重要的区别
实例化 ≠ 初始化
实例化:
new UserService();
只是:
把对象创建出来。
初始化:
属性注入完成之后,执行 Bean 的初始化逻辑。
🔴 和循环依赖的关系
Spring 能解决部分循环依赖的关键:
实例化
和
属性填充
不是同一个步骤。
所以可以:
new A()
↓
A对象已经存在
↓
提前暴露A
↓
再给A注入B
📚 一、什么是 Bean 生命周期?
例如:
@Service
public class UserService {
}
Spring 不只是简单执行:
new UserService();
而是经历一整套流程:
创建对象
↓
注入依赖
↓
初始化
↓
Spring管理
↓
正常使用
↓
销毁
这整个过程:
叫做:
Bean 生命周期。
二、第一步:实例化 Bean ⭐⭐⭐⭐⭐
例如:
@Service
public class UserService {
}
Spring 会先:
UserService userService =
new UserService();
这一步叫:
实例化(Instantiation)
此时:
对象:
已经存在
但是:
Bean 还没有完全创建完成。
例如:
@Service
public class UserService {
@Autowired
private OrderService orderService;
}
刚刚:
new UserService();
之后:
userService已经存在
但是:
orderService = null
因为:
依赖注入还没有开始。
所以:
对象实例化
≠
Bean创建完成
三、第二步:属性填充 / 依赖注入 ⭐⭐⭐⭐⭐
实例化完成之后:
Spring 开始给 Bean 注入依赖。
例如:
@Autowired
private OrderService orderService;
Spring:
查找OrderService
↓
获取OrderService Bean
↓
注入UserService
最后:
UserService
|
↓
OrderService
这一步:
叫做:
属性填充(Populate Properties)
也就是我们经常说的:
依赖注入 DI。
四、为什么实例化之后属性还是 null?
因为:
Spring 创建 Bean 是分阶段的。
先:
new UserService();
得到:
UserService对象
这个时候:
orderService = null
然后才:
属性填充
最终:
orderService = OrderService对象
所以:
实例化
↓
属性还是null
↓
依赖注入
↓
属性有值
五、这和循环依赖有什么关系? ⭐⭐⭐⭐⭐
假设:
A依赖B
B依赖A
字段注入:
class A {
@Autowired
private B b;
}
B:
class B {
@Autowired
private A a;
}
Spring 可以:
new A()
此时:
A已经存在
但是:
A.b = null
Spring 可以:
提前暴露A
然后:
创建B
B需要A:
拿到提前暴露的A
B创建完成。
再:
把B注入A
最终:
A → B
B → A
所以:
Spring 能解决部分循环依赖的重要原因就是:
实例化和属性填充是两个不同阶段。
六、第三步:Aware 回调
Spring 提供了一些:
Aware接口
例如:
BeanNameAware
BeanFactoryAware
ApplicationContextAware
作用:
让 Bean 感知 Spring 容器中的一些信息。
例如:
public class UserService
implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println(name);
}
}
Spring 会告诉:
UserService
↓
你在Spring里面叫什么名字
可以简单记:
Aware
=
让Bean知道Spring容器的信息
这个阶段:
知道即可。
七、第四步:BeanPostProcessor 前置处理 ⭐⭐⭐⭐⭐
BeanPostProcessor:
中文:
Bean 后置处理器。
虽然名字叫:
后置处理器
但是它有:
初始化前处理
和
初始化后处理。
核心方法:
postProcessBeforeInitialization()
表示:
初始化之前处理
流程:
Bean
↓
BeanPostProcessor
↓
初始化前处理
八、第五步:初始化 Bean ⭐⭐⭐⭐⭐
属性注入完成后:
开始执行初始化逻辑。
例如:
@PostConstruct
public void init() {
System.out.println("初始化");
}
可以做:
加载配置
初始化缓存
准备资源
检查参数
例如:
@Service
public class UserService {
@Autowired
private OrderService orderService;
@PostConstruct
public void init() {
System.out.println(
"UserService初始化完成"
);
}
}
执行顺序:
new UserService()
↓
注入OrderService
↓
执行@PostConstruct
九、实例化和初始化区别 ⭐⭐⭐⭐⭐
这是面试容易问的。
实例化
new UserService();
作用:
创建对象
初始化
例如:
@PostConstruct
作用:
对象已经创建
+
依赖已经注入
↓
执行初始化逻辑
所以:
实例化
↓
对象出现
初始化
↓
对象准备好使用
可以理解成:
实例化:
房子盖出来
属性填充:
家具搬进去
初始化:
检查水电、设备
Bean完成:
可以入住
十、第六步:BeanPostProcessor 后置处理 ⭐⭐⭐⭐⭐
初始化完成后:
执行:
postProcessAfterInitialization()
流程:
初始化完成
↓
BeanPostProcessor
↓
初始化后处理
这个阶段非常重要。
因为:
Spring 很多功能:
AOP
@Transactional
@Async
都和 Bean 后置处理机制密切相关。
十一、BeanPostProcessor 为什么重要?
假设:
@Service
public class UserService {
@Transactional
public void save() {
}
}
最开始:
new UserService()
得到:
原始UserService
但是:
因为:
@Transactional
Spring 可能需要:
创建代理对象。
最终:
UserService代理对象
|
↓
原始UserService
其他 Bean 注入的:
可能是:
代理对象
而不是最开始:
new出来的原始对象
所以:
BeanPostProcessor
是 Spring 非常重要的扩展机制。
十二、Bean 创建完成
经过:
实例化
↓
属性填充
↓
Aware
↓
初始化前处理
↓
初始化
↓
初始化后处理
Bean:
正式创建完成。
对于普通单例 Bean:
最终会进入:
singletonObjects
也就是:
一级缓存。
这和昨天学的三级缓存对应:
一级缓存
singletonObjects
↓
保存完整单例Bean
十三、Bean 正常使用
创建完成之后:
其他 Bean 可以:
@Autowired
private UserService userService;
获取它。
或者:
applicationContext.getBean(UserService.class);
此时:
Bean 处于:
正常使用阶段
十四、Bean 销毁
当:
Spring容器关闭
Bean 会进入销毁阶段。
例如:
@PreDestroy
public void destroy() {
System.out.println("销毁");
}
可以执行:
释放资源
关闭连接
停止线程
清理数据
流程:
Spring关闭
↓
@PreDestroy
↓
Bean销毁
十五、完整 Bean 生命周期 ⭐⭐⭐⭐⭐
把这张图记住:
Spring启动
↓
实例化Bean
↓
new UserService()
↓
属性填充
↓
@Autowired依赖注入
↓
Aware回调
↓
BeanPostProcessor
初始化前处理
↓
@PostConstruct等初始化
↓
BeanPostProcessor
初始化后处理
↓
Bean创建完成
↓
单例Bean进入一级缓存
↓
正常使用
↓
Spring容器关闭
↓
@PreDestroy
↓
Bean销毁
十六、Bean生命周期和三级缓存的关系 ⭐⭐⭐⭐⭐
你前面学过:
一级缓存
二级缓存
三级缓存
三级缓存主要发生在:
Bean创建过程中
关系:
Bean生命周期
|
↓
实例化
|
├────→ 提前暴露
| ↓
| 三级缓存
| ↓
| 循环依赖
|
↓
属性填充
↓
初始化
↓
BeanPostProcessor
↓
AOP代理
↓
完整Bean
↓
一级缓存
所以:
循环依赖不是独立知识点。
它实际上发生在:
Bean 生命周期创建阶段。
十七、Bean生命周期和AOP关系
例如:
@Transactional
public void save() {
}
Spring:
实例化原始Bean
↓
依赖注入
↓
初始化
↓
BeanPostProcessor处理
↓
创建AOP代理
↓
最终Bean
所以:
你从 Spring 容器拿到的:
UserService
可能实际上是:
代理对象
这也是为什么:
@Transactional
@Async
AOP
和 Bean 生命周期关系非常密切。
🎤 面试回答(30秒)
Spring Bean 的生命周期主要包括实例化、属性填充、Aware 回调、BeanPostProcessor 初始化前处理、初始化、BeanPostProcessor 初始化后处理、正常使用以及销毁。
Spring 首先实例化 Bean,然后进行依赖注入,之后执行相关 Aware 回调和初始化方法。在初始化前后 BeanPostProcessor 可以对 Bean 进行扩展处理,AOP 代理等功能就和这个扩展机制密切相关。Bean 创建完成后交给 Spring 容器管理,容器关闭时执行销毁逻辑。
🎯 面试追问
Q1:Bean 生命周期有哪些阶段?
答:
实例化
↓
属性填充
↓
Aware
↓
BeanPostProcessor前置
↓
初始化
↓
BeanPostProcessor后置
↓
使用
↓
销毁
Q2:实例化和初始化有什么区别?
答:
实例化:
new对象
初始化:
依赖注入完成以后
执行初始化逻辑
Q3:为什么实例化以后 @Autowired 属性还是 null?
答:
因为:
实例化
和
属性填充
是两个阶段。
先 new 对象:
再进行依赖注入。
Q4:BeanPostProcessor 是什么?
答:
Spring 提供的 Bean 扩展机制,可以在 Bean 初始化前后对 Bean 进行处理。
Q5:BeanPostProcessor 和 AOP 有什么关系?
答:
AOP 代理的创建和 BeanPostProcessor 机制密切相关,Spring 可以在 Bean 创建过程中将原始 Bean 包装成代理对象。
Q6:@PostConstruct 什么时候执行?
答:
依赖注入完成之后:
Bean 初始化阶段执行。
Q7:@PreDestroy 什么时候执行?
答:
Spring 容器关闭、Bean 销毁之前执行。
Q8:Bean 生命周期和循环依赖有什么关系?
答:
Spring Bean 的实例化和属性填充是两个阶段,所以 Bean 实例化后可以提前暴露引用,让其他 Bean 使用,从而解决部分循环依赖。
Q9:完整单例 Bean 最终放在哪里?
答:
一级缓存
singletonObjects
⚠️ 工作踩坑
1. 在构造方法里使用 @Autowired 对象
例如:
@Autowired
private OrderService orderService;
public UserService() {
orderService.query();
}
此时:
orderService可能还是null
因为:
构造方法执行
↓
对象实例化
↓
之后才进行@Autowired依赖注入
如果需要依赖注入完成后执行逻辑:
可以考虑:
@PostConstruct
2. 认为 new 出来就是完整 Bean
错误。
new UserService()
只是:
实例化
后面还有:
依赖注入
初始化
BeanPostProcessor
等过程。
3. 自己 new Spring Bean
例如:
UserService userService =
new UserService();
这个对象:
不是 Spring 容器创建的。
所以不会自动经历完整的 Spring Bean 管理流程。
例如:
@Autowired
@Transactional
@Async
AOP
等 Spring 能力可能不会按预期生效。
❓ 自测
-
什么是 Spring Bean 生命周期?
-
Bean 生命周期主要有哪些阶段?
-
什么叫实例化?
-
什么叫属性填充?
-
实例化和初始化有什么区别?
-
为什么刚 new 出来的 Bean 中 @Autowired 属性可能还是 null?
-
Aware 是干什么的?
-
BeanPostProcessor 是干什么的?
-
@PostConstruct 在什么时候执行?
-
@PreDestroy 在什么时候执行?
-
BeanPostProcessor 和 AOP 有什么关系?
-
Bean 生命周期和循环依赖有什么关系?
-
为什么字段循环依赖有机会通过提前暴露解决?
-
完整的单例 Bean 最终放在哪个缓存?
-
为什么自己 new 的对象和 Spring 管理的 Bean 不一样?