目录
一. 循环依赖的本质矛盾
1. 什么是循环依赖?
2. 矛盾的核心
二. 三级缓存架构解析
三级缓存工作流程图编辑
三、为什么必须三级缓存?
1. 二级缓存的致命缺陷
2. 三级缓存的精妙设计
四、场景推演:三级缓存如何解决代理问题
1. 正常流程(无循环依赖)
2. 循环依赖流程 编辑
五、源码级验证
1. 三级缓存获取逻辑
2. 代理对象生成点
六、如果强行使用二级缓存
在 Spring 框架中,循环依赖(Circular Dependency)是开发过程中最常见的陷阱之一。Spring 通过三级缓存机制优雅地解决了这一问题,但许多开发者会疑惑:为什么需要三级缓存?二级缓存能否实现同样的效果?本文将通过源码分析、场景推演和设计哲学,揭示这一机制背后的精妙设计。
一. 循环依赖的本质矛盾
1. 什么是循环依赖?
当两个或多个 Bean 相互依赖时,就会形成循环依赖:
// Bean A 依赖 Bean B
@Component
public class A {@Autowiredprivate B b;
}// Bean B 依赖 Bean A
@Component
public class B {@Autowiredprivate A a;
}
2. 矛盾的核心
-
构造器注入无法解决循环依赖:必须通过 Setter 或字段注入。
-
Bean 创建的生命周期冲突:
二. 三级缓存架构解析
Spring 通过三级缓存解决循环依赖问题,其核心数据结构如下:
缓存级别 | 数据结构 | 存储内容 |
---|---|---|
一级缓存 | singletonObjects | 完全初始化完成的单例 Bean |
二级缓存 | earlySingletonObjects | 提前暴露的早期 Bean(未完成属性注入) |
三级缓存 | singletonFactories | Bean 的 ObjectFactory(用于生成代理对象) |
三级缓存工作流程图
三、为什么必须三级缓存?
1. 二级缓存的致命缺陷
假设只有一级缓存 + 二级缓存:
-
场景:Bean A 依赖 Bean B,Bean B 依赖 Bean A,且 A 需要 AOP 代理
-
问题链:
-
A 实例化后放入二级缓存(原始对象)
-
B 从二级缓存获取 A 的原始对象并注入
-
A 完成初始化后需要生成代理对象
-
结果:B 中持有的是 A 的原始对象,与最终代理对象不一致
-
2. 三级缓存的精妙设计
通过 ObjectFactory
延迟处理代理:
// AbstractAutowireCapableBeanFactory
protected Object getEarlyBeanReference(String beanName, Object bean) {// 通过后置处理器生成代理对象return applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
-
动态决策:只有在发生循环依赖时才会调用 ObjectFactory
-
代理一致性:保证所有依赖方拿到的是同一个代理对象
四、场景推演:三级缓存如何解决代理问题
1. 正常流程(无循环依赖)
2. 循环依赖流程 
五、源码级验证
1. 三级缓存获取逻辑
// DefaultSingletonBeanRegistry
protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
2. 代理对象生成点
// AbstractAutowireCapableBeanFactory
protected Object doCreateBean(...) {// 1. 实例化对象instanceWrapper = createBeanInstance(beanName, mbd, args);// 2. 加入三级缓存addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 3. 属性填充(可能触发循环依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化(生成最终代理对象)exposedObject = initializeBean(beanName, exposedObject, mbd);
}
六、如果强行使用二级缓存?
假设合并三级缓存中的 singletonFactories
和 earlySingletonObjects
,会导致:
-
提前暴露未完成对象:可能将半成品 Bean 暴露给其他线程
-
代理对象不一致:普通 Bean 与代理 Bean 可能同时存在
-
内存泄漏风险:无法及时清理创建失败的 Bean 引用