一、循环依赖场景
假设存在两个Bean的相互依赖:
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Component
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
二、三级缓存定义
在 DefaultSingletonBeanRegistry
中定义:
// 一级缓存:完整Bean(K:Bean名称 V:实例化+初始化完成的Bean)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存:早期暴露对象(K:Bean名称 V:未完成属性注入的原始Bean)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 三级缓存:对象工厂(K:Bean名称 V:ObjectFactory)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
三、解决流程(以ServiceA和ServiceB为例)
1. 创建ServiceA
sequenceDiagram
participant Container
participant Cache1 as singletonObjects
participant Cache2 as earlySingletonObjects
participant Cache3 as singletonFactories
Container->>Cache1: 检查ServiceA是否存在
Cache1-->>Container: 不存在
Container->>Container: 实例化ServiceA(构造器调用)
Container->>Cache3: 添加ServiceA的ObjectFactory
Container->>Container: 开始属性注入(需要ServiceB)
关键代码段:
// AbstractAutowireCapableBeanFactory#doCreateBean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
2. 发现需要ServiceB
sequenceDiagram
participant Container
participant Cache1
participant Cache2
participant Cache3
Container->>Cache1: 检查ServiceB是否存在
Cache1-->>Container: 不存在
Container->>Container: 实例化ServiceB(构造器调用)
Container->>Cache3: 添加ServiceB的ObjectFactory
Container->>Container: 开始属性注入(需要ServiceA)
3. 解决ServiceB对ServiceA的依赖
sequenceDiagram
participant Container
participant Cache1
participant Cache2
participant Cache3
Container->>Cache1: 查找ServiceA
Cache1-->>Container: 不存在
Container->>Cache2: 查找ServiceA
Cache2-->>Container: 不存在
Container->>Cache3: 获取ServiceA的ObjectFactory
Container->>Container: 执行getEarlyBeanReference()
Container->>Cache2: 将生成的代理对象存入earlySingletonObjects
Container->>ServiceB: 注入ServiceA的早期引用
Container->>Container: 完成ServiceB初始化
Container->>Cache1: 将ServiceB放入singletonObjects
4. 回溯完成ServiceA初始化
sequenceDiagram
participant Container
participant Cache1
participant Cache2
participant Cache3
Container->>ServiceA: 注入已初始化的ServiceB
Container->>Container: 执行ServiceA的初始化后方法
Container->>Cache1: 将ServiceA放入singletonObjects
Container->>Cache2: 移除ServiceA的早期引用
Container->>Cache3: 移除ServiceA的ObjectFactory
四、关键机制详解
1. getEarlyBeanReference() 的核心作用
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
// 如果有必要,在此处生成代理对象
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
bean = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return bean;
}
2. 三级缓存必要性分析
缓存级别 | 解决的问题 | 典型场景 |
---|---|---|
singletonFactories | 处理AOP代理的延迟生成 | 需要保证代理对象的单例性 |
earlySingletonObjects | 避免重复创建早期引用 | 多个Bean依赖同一个未完成初始化的Bean |
singletonObjects | 存储最终可用Bean | 正常Bean获取 |
五、设计约束与限制
-
仅支持单例作用域
原型(prototype)作用域的Bean无法解决循环依赖,因为Spring不缓存原型Bean -
构造器注入限制
如果循环依赖通过构造器注入发生,无法解决(实例化前就需要完成依赖注入) -
异步初始化风险
使用@Async
等方法增强的Bean可能破坏初始化顺序
六、调试技巧
-
查看缓存状态
在DefaultSingletonBeanRegistry
类中设置断点:// 查看三级缓存内容 System.out.println("singletonFactories: " + singletonFactories.keySet()); System.out.println("earlySingletonObjects: " + earlySingletonObjects.keySet()); System.out.println("singletonObjects: " + singletonObjects.keySet());
-
强制抛出循环依赖异常
在配置类添加:@Bean public CircularReferencesBean circularReferencesBean() { return new CircularReferencesBean(circularReferencesBean()); }
七、性能优化建议
-
避免过度使用循环依赖
即使技术可行,也应通过设计模式(如事件驱动)解耦 -
合理使用@Lazy注解
延迟加载非必要依赖:@Autowired @Lazy private ServiceB serviceB;
-
监控缓存命中率
通过JMX监控singletonObjects
与earlySingletonObjects
的比例
总结:Spring的三级缓存机制通过 提前暴露对象引用 + 动态代理生成 的协同设计,在保证单例性的前提下,优雅地解决了循环依赖问题。理解该机制需要重点把握Bean生命周期的阶段划分和缓存状态的转换逻辑。