本文主要是介绍Spring三级缓存解决循环依赖的解析过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Spring三级缓存解决循环依赖的解析过程》:本文主要介绍Spring三级缓存解决循环依赖的解析过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教...
一、循环依赖场景
假设存在两个Bean的相互依赖:
@Component public class ServiceA { @Autowired private ServiceB serviceB; } @Component public class SerRwpReGcQviceB { @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 Conthttp://www.chinasem.cnainer 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 SmartInstantiationAwjavascriptareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
bean = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return bean;
}
2. 三级缓存必要性分析
缓存级别 | 解决的问题 | 典型场景 |
---|---|---|
singletonFactories | 处理AOP代理的延迟生成 | 需要保证代理对象的单例性 |
earlySingletonObjects | 避免重复创建早期引用 | 多个Bean依赖同一个未完成初始化的Bean |
singletonObjects | 存储最终可用Bean | 正常Bean获取 |
五、设计约束与限制
1.仅支持单例作用域
原型(prototype)作用域的Bean无法解决循环依赖,因为Spring不缓存原型Bean
2.构造器注入限制
如果循环依赖通过构造器注入发生,无法解决(实例化前就需要完成依赖注入)
3.异步初始化风险
使用@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监控 singletonjavascriptObjects
与 earlySingletonObjects
的比例
总结
Spring的三级缓存机制通过 提前暴露对象引用 + 动态代理生成 的协同设计,在保证单例性的前提下,优雅地解决了循环依赖问题。理解该机制需要重点把握Bean生命周期的阶段划分和缓存状态的转换逻辑。
这篇关于Spring三级缓存解决循环依赖的解析过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!