Spring如何解决循环依赖的问题
在Java面试中,Spring框架的循环依赖处理机制几乎是必考题。今天我们就来聊聊这个高频面试题背后的实现原理,帮你彻底搞懂Spring的三级缓存设计!
📌 2025年最新Java面试宝典合集
🔵 链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g
提取码: 9b3g
🔄 什么是循环依赖
举个🌰:Bean A依赖Bean B,同时Bean B又依赖Bean A。这种"鸡生蛋还是蛋生鸡"的问题在Spring初始化时就会报BeanCurrentlyInCreationException。
graph LR
A[Bean A] -->|依赖| B[Bean B]
B -->|依赖| A
⚙️ Spring的三级缓存机制
Spring通过三级缓存巧妙破局,核心在DefaultSingletonBeanRegistry中定义:
- singletonObjects(一级缓存):存放完全初始化的Bean
- earlySingletonObjects(二级缓存):存放半成品Bean(已实例化未注入属性)
- singletonFactories(三级缓存):存放Bean工厂对象
🛠️ 解决循环依赖的实战流程
假设现在有A和B互相依赖:
-
创建Bean A
- 实例化A(此时还是个空对象)
- 将A的工厂对象放入三级缓存
- 开始给A注入属性...
-
发现需要Bean B
- 暂停A的属性注入
- 转向创建Bean B
-
创建Bean B
- 实例化B(空对象)
- 将B的工厂对象放入三级缓存
- 给B注入属性时发现需要Bean A!
-
关键转折点 🔑
- 从三级缓存拿到A的工厂对象
- 通过
getEarlyBeanReference()生成早期引用 - 把A的早期引用放入二级缓存,同时移除三级缓存中的工厂
-
完成Bean B创建
- 将完整B放入一级缓存
- 回到Bean A的属性注入流程
-
最终闭环 ✅
- A成功注入B实例
- 将完整A放入一级缓存
- 清理二级缓存中的临时对象
🚫 哪些循环依赖Spring解决不了
- 构造器注入的循环依赖
// 这种直接报错! @Component public class A { private final B b; public A(B b) { this.b = b; } } - @Async代理对象的循环依赖
- Prototype作用域的Bean循环依赖
💡 高频面试应答技巧
当面试官问:"Spring怎么解决循环依赖?"建议这样回答:
_"Spring通过三级缓存机制处理单例Bean的setter循环依赖。具体来说:
- 在Bean实例化后,会提前暴露ObjectFactory到三级缓存
- 当发生循环依赖时,通过三级缓存获取早期引用
- 解决了属性注入阶段的依赖闭环问题
不过要注意,构造器注入的循环依赖是无解的"_
🎁 福利时间
准备Java面试需要系统化的题库训练!通过 面试鸭返利网 开通面试鸭会员可返利25元,海量真实大厂题库+详细题解助你快速通关:

✨ 小提示:在面试鸭刷题时遇到Spring循环依赖相关问题,记得结合三级缓存的源码分析(
AbstractAutowireCapableBeanFactory#doCreateBean),绝对加分!


