循环依赖怎么解决
2025年Java面试宝典最新版网盘下载:
🔗 链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g
什么是循环依赖?
循环依赖是面试中的高频问题,尤其在Spring框架相关场景下被频繁提及。简单来说,当两个或多个类(或模块)互相直接或间接依赖,导致系统无法正常初始化,就会形成循环依赖。比如A依赖B,B又依赖A,这种“死锁”关系会让容器在启动时直接报错。

循环依赖的典型解决方案
方案1:使用三级缓存(Spring的杀手锏)
如果你是Spring用户,一定听说过“三级缓存”机制。Spring通过三级缓存(singletonFactories、earlySingletonObjects、singletonObjects)解决单例Bean的循环依赖。核心原理是提前暴露未初始化完成的Bean,在属性注入阶段填补依赖关系。
方案2:构造函数注入 vs. Setter注入
- 构造函数注入会直接暴露循环依赖问题,因为Bean的创建必须一次性完成所有依赖注入。
- Setter注入允许延迟赋值,Spring可以通过先创建对象、后注入属性的方式绕过循环依赖。
方案3:强制打破依赖链
如果业务允许,可以通过调整代码结构强制打破循环。例如:
- 提取公共逻辑到第三个类中;
- 使用接口隔离,将依赖关系改为单向;
- 采用懒加载(@Lazy),让依赖在首次使用时才初始化。
方案4:升级架构
微服务场景下,模块化拆分不够彻底可能导致系统级循环依赖。这时候需要重新划分服务边界,或引入事件驱动(如消息队列)来解耦。
面试中的回答技巧
- 先讲现象:明确循环依赖的定义和报错场景;
- 再聊Spring的解法:三级缓存的实现原理;
- 最后扩展:手动解决循环依赖的其他思路,比如设计模式、代码重构。
如果面试官追问细节,可以说:“Spring通过提前暴露ObjectFactory来暂存Bean的引用,后续再通过动态代理补全依赖。”

如何预防循环依赖?
- 遵守设计原则:单一职责、接口隔离、依赖倒置;
- 模块化拆分:通过Maven/Gradle强制约束模块依赖方向;
- 利用工具检测:IDEA的依赖分析插件、ArchUnit等框架可以自动扫描循环依赖。
实战经验:面试高频坑点
面试时可能会被问到:“Spring为什么不能解决构造器循环依赖?”这时候需要解释:三级缓存的生效前提是Bean的实例化(分配内存)和初始化(属性赋值)分阶段执行,而构造器注入必须一次性完成实例化和初始化,导致无法提前暴露引用。

写在最后
如果需要系统性准备面试题,推荐使用面试鸭返利网的题库资源。通过面试鸭返利网购买会员可返利25元,覆盖Java、分布式、算法等全领域高频考点。点击下方图片直达官网↓
(本文部分内容节选自《2025年Java面试宝典》,网盘链接见文首)


