Spring Bean 生命周期与循环依赖
❓ 面试官:能详细说说 Spring Bean 的生命周期吗?从创建到销毁经历了哪些步骤?
频率:🔥🔥🔥🔥🔥
💡 一句话总结(先抛结论): Spring Bean 的生命周期包括:实例化 → 属性填充 → 初始化 → 使用 → 销毁。其中初始化阶段会执行 @PostConstruct、InitializingBean、init-method 等方法。
📝 详细生命周期流程(面试必背):
实例化(Instantiation):
- Spring 通过反射调用构造器创建 Bean 实例。
属性填充(Populate Properties):
- 通过
@Autowired、@Value等注解注入依赖。
- 通过
初始化前(Before Initialization):
- 执行
BeanPostProcessor.postProcessBeforeInitialization()。
- 执行
初始化(Initialization):
- 执行
@PostConstruct注解的方法。 - 执行
InitializingBean.afterPropertiesSet()。 - 执行自定义的
init-method。
- 执行
初始化后(After Initialization):
- 执行
BeanPostProcessor.postProcessAfterInitialization()(AOP 代理就是在这里创建的)。
- 执行
使用阶段:
- Bean 可以被正常使用了。
销毁(Destroy):
- 容器关闭时,执行
@PreDestroy、DisposableBean.destroy()、自定义destroy-method。
- 容器关闭时,执行
🌟 实战应用(加分项): "在项目中,我们经常在 @PostConstruct 方法里做一些初始化工作,比如加载配置、预热缓存。在 @PreDestroy 方法里做资源清理,比如关闭线程池、释放连接。"
❓ 面试官:Spring 是如何解决循环依赖的?能详细说说三级缓存机制吗?【中级】
频率:🔥🔥🔥🔥🔥
💡 一句话总结(先抛结论): Spring 通过三级缓存(三个 Map)来解决循环依赖问题。核心思想是:提前暴露半成品的 Bean(只完成了实例化,还没完成属性填充),让其他 Bean 可以先拿到这个半成品,完成自己的初始化。
📝 三级缓存详解:
假设有两个类互相依赖:
UserService依赖OrderServiceOrderService依赖UserService
三级缓存结构:
java
// 一级缓存:存放完整的单例 Bean(成品)
singletonObjects
// 二级缓存:存放半成品 Bean(提前暴露的,用于解决循环依赖)
earlySingletonObjects
// 三级缓存:存放 Bean 工厂(用于生成 AOP 代理对象)
singletonFactories解决流程(简化版):
- 创建
UserService:实例化后,放入三级缓存(工厂对象)。 - 填充
UserService属性时,发现需要OrderService。 - 创建
OrderService:实例化后,放入三级缓存。 - 填充
OrderService属性时,发现需要UserService。 - 从三级缓存中拿到
UserService的工厂,创建半成品UserService,放入二级缓存。 OrderService拿到半成品UserService,完成自己的初始化,放入一级缓存。UserService拿到完整的OrderService,完成自己的初始化,放入一级缓存。
🌟 为什么需要三级缓存? "如果只有两级缓存,当存在 AOP 代理时,无法区分是返回原始对象还是代理对象。三级缓存通过工厂模式,可以在需要时动态创建代理对象,保证循环依赖时也能正确生成 AOP 代理。"