2025年Java面试宝典,点击领取
(网盘链接长期有效,建议保存到个人账号)
Spring如何解决循环依赖的原理
咱们做Java开发的都知道,循环依赖是个经典的面试坑点。最近有个学员去某大厂面试时被连环追问:"Spring到底怎么处理Bean之间的循环依赖?"、"为什么构造器注入解决不了循环依赖?"。今天咱们就用最接地气的方式,掰开揉碎讲清楚这个高频考点。
一、什么是循环依赖
举个生活化的例子:张三的工牌照片需要李四帮忙拍,但李四说必须看到张三的工牌才能进办公楼拍照。这就形成了"张三依赖李四,李四又依赖张三"的死循环。
在Spring容器里,类似这样的场景就是:
- Bean A的创建需要注入Bean B
- Bean B的创建又需要注入Bean A
- 此时就形成了循环依赖闭环

二、三级缓存机制
Spring解决这个问题的核心在于三级缓存设计。咱们可以把这三级缓存想象成三个办事窗口:
- 一级缓存(成品库):存放完全初始化好的Bean
- 二级缓存(半成品库):存放已实例化但未完成初始化的Bean
- 三级缓存(生产车间):存放生成Bean的工厂对象
具体处理流程分四步走:
- 创建Bean A时,先在三级缓存登记工厂
- 当需要注入Bean B时,发现B不存在,立即开始创建B
- 创建B时需要注入A,此时能从三级缓存拿到A的早期引用
- B创建完成后,A继续完成属性注入和初始化

三、为什么构造器注入无法解决
很多同学面试时栽在这个问题上。其实道理很简单:
- 构造器注入发生在实例化阶段
- 此时Bean还未放入三级缓存
- 当两个Bean都通过构造器注入时,双方都无法获取对方的引用
这就好比两个人都站在银行柜台前说:"他不存钱,我就不转账",结果谁都完成不了交易。
四、实战应用建议
虽然Spring解决了大部分循环依赖问题,但在实际开发中:
- 尽量避免循环依赖(代码结构问题)
- 优先使用setter注入而非构造器注入
- 对于必须使用构造器注入的场景,考虑@Lazy延迟加载

准备面试的同学注意,这道题往往会追问到源码层面。建议大家重点理解DefaultSingletonBeanRegistry这个类,特别是其中的三个Map结构。
需要开通**面试鸭会员**的同学注意啦!通过面试鸭返利网购买可享25元返利,相当于用白菜价拿到全站题库+解析。结合前面分享的面试宝典,春招秋招绝对能横扫一片!


