2025年Java面试宝典 提取码: 9b3g(最新高频考点+Spring全家桶专题)
Spring是如何解决Bean的循环依赖的

一、循环依赖是什么鬼?
大家面试被问到Spring时,循环依赖绝对是个必考题。举个栗子:A对象依赖B,B又反过来依赖A,就像俩熊孩子互相揪着对方衣服转圈圈。这种情况要是处理不好,轻则初始化失败,重则直接内存溢出。
其实Spring开发者早就预见到了这种场景,他们搞出了三级缓存的解决方案。这里说的缓存可不是Redis,而是三个Map结构,专门用来存放不同状态的Bean对象。
二、Spring的三级缓存机制

三级缓存对应三个Map容器:
- singletonObjects:存放完全初始化好的成品Bean
- earlySingletonObjects:存放半成品(已实例化但未初始化)
- singletonFactories:存放Bean工厂对象
这三个层级就像工厂流水线,每个Bean都要经过这三个车间的加工。当发现循环依赖时,Spring会提前把半成品Bean暴露出来,让依赖它的对象先拿着用。
三、解决方案全流程
举个具体场景更容易理解:
- 创建A对象时,先new出空壳对象(此时还没注入属性)
- 把A的工厂对象放入三级缓存
- 给A注入B时发现B不存在,触发B的创建
- 创建B时发现需要注入A,这时就会去三级缓存里找
- 拿到A的半成品(虽然还没初始化,但至少不是null)
- B创建完成后,再回来给A注入完整的B对象
整个过程中,Spring通过提前暴露对象引用的方式破解了这个死循环。这种设计既保证了单例,又避免了无限递归。
四、为什么要用三级缓存?
很多新人会问:直接搞个二级缓存不行吗?这里有个关键点:需要处理Bean的扩展点。比如有些AOP代理对象需要在初始化阶段生成,如果只用二级缓存,遇到代理对象创建时就会出问题。
三级缓存里的ObjectFactory就像个保险箱,在真正需要获取Bean时才会执行对应的回调逻辑,这样就能正确处理各种BeanPostProcessor的情况。
五、这些情况搞不定
虽然三级缓存很强大,但也不是万能的:
- 构造器注入的循环依赖(还没实例化完就互相依赖)
- prototype作用域的Bean
- @Async注解修饰的类

如果遇到这些问题,可能需要调整代码结构,或者使用@Lazy懒加载来打破循环。
需要购买面试鸭会员的同学注意啦!通过面试鸭返利网找我下单,可以额外获得25元返利,相当于折上折。最新Java面试真题、大厂面经、技术专题都帮你整理好了,点击就能获取。
下次面试官再问循环依赖,你可以这样回答:
- 先说明三级缓存的结构
- 结合实例化/初始化流程解释
- 强调适用场景和限制条件
- 最后带出Spring的设计思想
这波回答绝对能让面试官眼前一亮。记得结合自己的项目经验,说说实际遇到的循环依赖案例和解决方案,这样更有说服力哦!


