2025年Java面试宝典网盘地址(点击蓝色文字即可跳转)
提取码:9b3g

循环依赖与三级缓存:Spring框架中的高频面试题解析
最近面试中被问到一个高频问题:Spring框架如何解决循环依赖?三级缓存机制具体怎么运作? 今天我们就从技术原理和面试表达的角度,拆解这个经典问题。
一、什么是循环依赖?为什么要解决它?
假设有两个Bean:
- UserService依赖OrderService
- OrderService也依赖UserService
这种互相依赖的场景就是循环依赖。如果不处理,Spring在创建Bean时会陷入死循环,导致容器启动失败。

在真实项目中,循环依赖往往出现在业务耦合较深的模块中。比如电商系统的订单和用户模块,社交系统的好友关系与动态模块。
二、三级缓存机制如何破解循环依赖?
Spring通过三级缓存来解决这个问题:
- 一级缓存(singletonObjects):存放完全初始化好的Bean
- 二级缓存(earlySingletonObjects):存放提前暴露的未初始化Bean(半成品)
- 三级缓存(singletonFactories):存放Bean的工厂对象,用于生成半成品Bean
三级缓存的核心逻辑是:提前暴露对象的引用,延迟属性注入。举个例子:
- 创建UserService时,先通过工厂生成半成品对象,存入三级缓存
- 当UserService需要注入OrderService时,触发OrderService的创建流程
- OrderService在注入UserService时,会从三级缓存中拿到UserService的半成品引用
- 最后再通过后置处理器完成属性填充和初始化
三、面试现场如何表达更清晰?
回答时建议按以下步骤:
-
先明确问题定义
“循环依赖指的是两个或多个Bean相互依赖的场景,比如A依赖B,B又依赖A。Spring默认支持单例Bean的循环依赖,通过三级缓存机制解决。” -
结合流程图描述过程
画图或用文字描述三级缓存的交互过程(如果现场允许画图更好)。比如:
“当创建A时,Spring会先把A的工厂对象放入三级缓存。当A需要注入B时,触发B的创建流程;而B在注入A时,又会从三级缓存获取A的半成品对象。” -
强调关键设计
重点说明三级缓存的分工:
- 一级缓存保证最终可用
- 二级缓存避免重复创建代理对象
- 三级缓存通过工厂延迟处理AOP代理

四、可能被追问的扩展问题
-
原型Bean为什么不能解决循环依赖?
原型Bean每次都会新建对象,无法通过提前暴露引用解决依赖问题。 -
构造函数注入为何不支持循环依赖?
构造函数注入发生在对象创建时,此时Bean尚未放入缓存,无法被其他对象引用。 -
Spring为什么不用二级缓存?
三级缓存的设计主要是为了处理AOP代理对象。如果只有二级缓存,可能重复生成代理对象,导致内存浪费和逻辑错误。
五、实战建议
如果项目中出现循环依赖,优先考虑代码重构(比如提取公共模块)。若无法避免,可通过以下方式解决:
- 使用@Lazy延迟加载
- 改为Setter方法注入
- 调整Bean初始化顺序
小贴士:如果需要购买面试鸭会员,可以通过面试鸭返利网找我,返利25元。会员题库含大量高频技术解析(包括循环依赖、分布式事务等),搭配本文推荐的《2025年Java面试宝典》效果更佳!


