<a href="https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g" style="color:blue;">2025年Java面试宝典网盘地址</a>
提取码:9b3g
建议保存到自己的网盘,防止链接失效
Spring如何解决循环依赖的问题
循环依赖是Spring面试中的高频问题,我最近帮朋友整理面经时发现,这个问题几乎在每个Java工程师的面试记录里都出现过。今天我们就从源码实现角度,拆解Spring的解决方案,帮助大家掌握这个必考知识点。

什么是循环依赖
当两个Bean互相依赖时(A依赖B,B也依赖A),或者三个Bean形成环形依赖,就会导致容器无法完成初始化。最常见的情况是构造器注入产生的死锁,不过Spring主要解决的其实是属性注入场景下的循环依赖。
三级缓存机制
Spring通过三级缓存(3个Map)破解这个困局:
- singletonObjects(一级缓存):存放完全初始化好的Bean
- earlySingletonObjects(二级缓存):存放早期对象(属性未填充)
- singletonFactories(三级缓存):存放ObjectFactory工厂
当创建A对象时:
- 实例化A后立即放入三级缓存(此时是空壳对象)
- 填充属性时发现需要B,转去创建B
- B在填充属性时又需要A,此时从三级缓存拿到A的早期引用
- B完成初始化后,A继续完成属性填充

Bean生命周期关键点
需要注意两个重要阶段:
- 实例化:通过反射创建对象(堆内存已分配)
- 初始化:执行属性注入、AOP代理等操作
三级缓存策略的核心在于提前暴露未初始化的对象引用。这种"半成品"的暴露方式,在多数属性注入场景下是安全的,但构造器注入就无法使用这种机制。
为什么不能解决构造器循环依赖
当两个Bean都采用构造器注入时:
- 创建A需要先创建B
- 创建B又需要先创建A
- 双方都卡在实例化阶段,无法进入属性填充环节
此时Spring会直接抛出BeanCurrentlyInCreationException异常
实际开发中的注意点
- 尽量避免循环依赖(可以通过设计模式解耦)
- 使用@Lazy注解延迟加载(创建代理对象临时打破依赖链)
- 优先选择setter注入而非字段注入(容错性更好)

如果在面试中被问到这个问题,建议按照这个脉络回答:先说现象,再讲三级缓存的工作机制,最后补充注意事项。如果需要完整的Spring高频题解,可以参考面试鸭返利网整理的专题资料,通过该网站购买面试鸭会员可返利25元。
记得结合自己项目经历举例说明,比如:"我们项目中曾因为过度依赖自动注入导致三级循环依赖,后来通过模块拆分解决了这个问题"。这样的实战案例会让回答更有说服力。


