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

深度解析 Spring Boot 循环依赖:原理、源码与解决方案

在 Spring Boot 开发中,循环依赖是一个常见且容易被忽视的技术点。当两个或多个 Bean 相互引用时,就会形成循环依赖(如 A 依赖 B,B 依赖 A)。初学者往往会困惑:Spring 为什么能自动处理这种看似矛盾的依赖关系?本文将从原理、源码实现到解决方案,全方位剖析 Spring Boot 的循环依赖机制。

一、什么是循环依赖?

循环依赖指的是两个或多个 Bean 之间存在相互引用的关系,形成闭环。例如:

// ServiceA依赖ServiceB
@Service
public class ServiceA {@Autowiredprivate ServiceB serviceB;
}// ServiceB依赖ServiceA
@Service
public class ServiceB {@Autowiredprivate ServiceA serviceA;
}

上述代码中,ServiceA需要注入ServiceB,而ServiceB同时需要注入ServiceA,形成了最简单的循环依赖。在传统的对象创建过程中,这种相互依赖会导致 "先有鸡还是先有蛋" 的悖论,但 Spring 通过特殊的机制解决了大部分场景下的循环依赖问题。

二、Spring Boot 如何处理循环依赖?

Spring 容器对循环依赖的处理能力,是其 Bean 管理机制的重要体现。核心解决方案可概括为:三级缓存 + 提前暴露半成品 Bean

1. 三级缓存的核心作用

Spring 通过三个缓存(实际上是三个 Map)来协调 Bean 的创建与依赖注入过程,这三个缓存定义在DefaultSingletonBeanRegistry中:

// 一级缓存:存储完全初始化完成的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:存储半成品Bean(已实例化但未完成属性注入和初始化)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三级缓存:存储Bean的工厂对象,用于生成半成品Bean的代理对象
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  • 一级缓存(singletonObjects):存放已完成所有初始化步骤的 Bean,是最终可被使用的成品 Bean。
  • 二级缓存(earlySingletonObjects):存放已实例化但尚未完成属性注入和初始化的半成品 Bean,用于解决循环依赖时的临时引用。
  • 三级缓存(singletonFactories):存放ObjectFactory对象,该工厂用于在需要时生成 Bean 的早期引用(可能是原始对象或代理对象)。

2. 循环依赖的解决流程

以ServiceA和ServiceB的循环依赖为例,Spring 的处理流程如下:

  1. 创建 ServiceA
    1. 调用getBean(ServiceA),检查一级缓存,未命中。
    2. 实例化ServiceA(通过构造方法创建对象,但未注入属性)。
    3. 将ServiceA的ObjectFactory放入三级缓存(singletonFactories)。
    4. 开始为ServiceA注入属性,发现依赖ServiceB。
  2. 创建 ServiceB
    1. 调用getBean(ServiceB),检查一级缓存,未命中。
    2. 实例化ServiceB,将其ObjectFactory放入三级缓存。</
http://www.xdnf.cn/news/17429.html

相关文章:

  • Python vs MATLAB:智能体开发实战对比
  • JavaScript 变量:数据存储的核心机制
  • 生产环境中Spring Cloud Sleuth与Zipkin分布式链路追踪实战经验分享
  • 消息生态系统全景解析:技术架构、核心组件与应用场景
  • Tomcat报错-chcon无法关联自启脚本
  • MySQL(189)如何分析MySQL的锁等待问题?
  • 采用GPT5自动规划实现番茄计时器,极简提示词,效果达到产品级
  • 祝融号无线电工作频段
  • 繁花深处:花店建设的时代意义与多元应用—仙盟创梦IDE
  • keil之stm32f10x模板工程创建
  • 简要介绍交叉编译工具arm-none-eabi、arm-linux-gnueabi与arm-linux-gnueabihf
  • 【重建技巧】Urban Scene Reconstruction-LoD细节提升
  • 【unitrix数间混合计算】2.9 小数部分特征(bin_frac.rs)
  • 第十四届蓝桥杯青少年组省赛 编程题真题题解
  • [SC]高效地调试SystemC模型中的语法错误
  • AI大模型模态特征详解
  • 【ref、toRef、toRefs、reactive】
  • Qt Graphics View框架概述
  • Redis 事务机制
  • Sklearn 机器学习 数据降维PCA 指定方差百分比计算分量数
  • 生态问题是什么?
  • C++ 虚函数、多重继承、虚基类与RTTI的实现成本剖析
  • 徘徊识别场景误报率↓77%:陌讯动态时序建模方案实战解析
  • Linux网络转发系统框架分析
  • 强化学习概论(1)
  • 生产环境某业务服务JVM调优总结
  • 关于C语言本质的一些思考
  • 计算BERT-BASE参数量
  • 驾驶场景玩手机识别准确率↑32%:陌讯动态特征融合算法实战解析
  • 数据结构——优先级队列(PriorityQueue):一文解决 Top K 问题!