当前位置: 首页 > news >正文

Spring三级缓存解决循环依赖的深度解析

一、循环依赖场景

假设存在两个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获取

五、设计约束与限制
  1. 仅支持单例作用域
    原型(prototype)作用域的Bean无法解决循环依赖,因为Spring不缓存原型Bean

  2. 构造器注入限制
    如果循环依赖通过构造器注入发生,无法解决(实例化前就需要完成依赖注入)

  3. 异步初始化风险
    使用@Async等方法增强的Bean可能破坏初始化顺序


六、调试技巧
  1. 查看缓存状态
    DefaultSingletonBeanRegistry 类中设置断点:

    // 查看三级缓存内容
    System.out.println("singletonFactories: " + singletonFactories.keySet());
    System.out.println("earlySingletonObjects: " + earlySingletonObjects.keySet());
    System.out.println("singletonObjects: " + singletonObjects.keySet());
    

  2. 强制抛出循环依赖异常
    在配置类添加:

    @Bean
    public CircularReferencesBean circularReferencesBean() {
        return new CircularReferencesBean(circularReferencesBean());
    }
    


七、性能优化建议
  1. 避免过度使用循环依赖
    即使技术可行,也应通过设计模式(如事件驱动)解耦

  2. 合理使用@Lazy注解
    延迟加载非必要依赖:

    @Autowired
    @Lazy
    private ServiceB serviceB;
    

  3. 监控缓存命中率
    通过JMX监控 singletonObjectsearlySingletonObjects 的比例


总结:Spring的三级缓存机制通过 提前暴露对象引用 + 动态代理生成 的协同设计,在保证单例性的前提下,优雅地解决了循环依赖问题。理解该机制需要重点把握Bean生命周期的阶段划分和缓存状态的转换逻辑。

相关文章:

  • ar头显和眼镜图像特效处理
  • 蓝桥杯模拟题--约数的个数(约数和质因数的区别)
  • 【PCB工艺】时序图(Timing Diagram)
  • visual studio 2017配置QT5.9.4环境
  • DeepSeek绘画工程与第三方通道整合架构解析
  • 【越南体育比分系统开发实战 | 全栈技术解析+7天极速交付方案】
  • python深度评测:5大中文长度计算方案终极对决(你的选择可能一直是错的)
  • Mininet--topo.py-预定义拓扑图解析
  • docker数据卷挂载,安全与优化隔离,docker Compose
  • Visual Studio Code(简称 VS Code)下载与使用教程1(新建文件,语法高亮,快捷键,主题,快捷指令)
  • 猎豹移动营收连续三季增长,AI驱动的猎豹成绩单怎么分析?
  • String类的使用
  • EFISH-SBC-RK3576 + 5G模组:无线工业相机与分布式AI质检‌
  • 手动实现 Spring 底层机制 【初始化 IOC容器+ 依赖注入+BeanPostProcessor 机制+AOP】
  • 算法基础——模拟
  • 【QT5 多线程示例】线程池
  • Python模块与包管理完全指南
  • 时序逻辑电路
  • Linux——线程安全
  • 一文了解 MCP Server:AI 工具与外部世界的桥梁
  • 如何做阿里巴巴国际网站/百度seo指南
  • 合肥网站网站建设/今日关键词
  • 织梦转WordPress插件/网络推广seo教程
  • 江西赣州疫情最新情况/优化人员是什么意思
  • 做设计找素材都有什么网站/百度竞价排名是什么方式
  • 营销型网站套餐/谷歌浏览器下载电脑版