Spring解决循环依赖的原理是Java面试高频考点,通过三级缓存机制巧妙处理单例Bean的相互依赖问题。一级缓存存储完整Bean,二级缓存存放半成品引用,三级缓存保存Bean工厂对象。当Bean A依赖B时,Spring会先暂存A的半成品到三级缓存,待B创建时通过缓存获取A的引用,从而打破循环。需要注意的是构造器注入和原型Bean的循环依赖无法解决。掌握这一机制不仅能应对面试,更能深入理解Spring IoC容器的工作流程,帮助开发者处理复杂依赖关系。
作为一名Java开发者,在面试中被问及 Spring循环依赖 的原理是家常便饭。很多同学对这个概念一知半解,今天我们就以面试口述的形式,深入浅出地聊聊 Spring循环依赖 的核心解决机制。
🔥 2025最新Java面试宝典领取(限时福利):
<font color="blue">链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g</font>
简单说,就是两个或多个Bean互相引用对方,形成了“鸡生蛋蛋生鸡”的死锁局面。比如:
@Service
public class AService {
@Autowired
private BService bService; // A 依赖 B
}
@Service
public class BService {
@Autowired
private AService aService; // B 又依赖 A
这种 循环依赖 场景在单例模式下,如果处理不当会导致容器启动失败。
Spring通过 三级缓存 机制巧妙解决了单例Bean的 循环依赖 问题。这三个缓存容器分别是:
singletonObjects
(一级缓存)
存放 完全初始化 好的Bean实例。成品仓库。
earlySingletonObjects
(二级缓存)
存放 提前暴露 的半成品Bean(仅实例化,未填充属性)。过渡区。
singletonFactories
(三级缓存)
存放 Bean工厂对象(ObjectFactory
),用于动态创建代理对象。生产线。
假设A和B发生循环依赖,Spring容器启动时是这样处理的:
创建A实例(半成品)
new AService()
singletonFactories
)填充A的属性(发现依赖B)
创建B实例(半成品)
new BService()
填充B的属性(发现依赖A!)
完成B的初始化
继续初始化A
经过这个过程,A和B这对互相依赖的对象成功完成初始化,循环依赖 被完美解决。
只支持单例模式
原型Bean(prototype)的循环依赖会直接抛出 BeanCurrentlyInCreationException
。
构造器循环依赖无解
如果依赖通过构造器注入(而非Setter),三级缓存机制失效:
public AService(BService bService) {...} // 构造器依赖
此时Spring会检测到死循环并报错。
AOP代理的特殊处理
如果Bean需要被代理(如AOP切面),Spring会通过 SmartInstantiationAwareBeanPostProcessor
在三级缓存中提前生成代理对象(如下图流程):
当面试官问:“Spring如何解决循环依赖?” 可以这样回答:
“Spring通过三级缓存机制解决单例Bean的循环依赖问题。核心是提前暴露半成品Bean:
- 一级缓存放成品Bean;
- 二级缓存放提前暴露的引用(防重复代理);
- 三级缓存存生成Bean的工厂。
当Bean A依赖B时,会先暂存A的半成品到三级缓存,等B创建时就能从缓存拿到A的引用。
注意构造器注入的循环依赖无法解决,原型Bean也不行。”
🉐 小贴士:需要系统刷Java面试题的同学,推荐通过 面试鸭返利网 购买面试鸭会员,可返利25元!海量真题解析和项目难点剖析一网打尽👇
理解 Spring循环依赖 的解决原理,不仅能应对面试,更能加深对IoC容器工作流程的掌握。遇到复杂依赖关系时,你就能快速定位问题根源。
扫码联系我返利
(当前返利8元,金额随官方实际价格波动,最好提前咨询)
面试鸭小程序码
美团大额优惠券,给自己加个鸡腿吧!
今日有支付宝大红包赶快领,手慢无
支付宝扫码领取1-8元无门槛红包