Spring 循环依赖(circular dependency)

[Spring]用100行代码来模拟解决Spring的循环依赖问题 Abstract 好久没写文章了, 最近喜欢上了springboot, 也发现这个开发起来确实很方便和快捷。 包括spring kafka, jdbc, & actuator. 一天, 比较惊讶于spring如何优雅的解决循环依赖的问题的, 因为自己代码有时候也没注意, @Autowired 到处都是, 但是发现spring竟然可以正常工作,于是好奇的想了解下其实现。 所以就有了这个文章。 Spring如何解决循环依赖的? 官方文档:here Circular dependencies If 阅读详情

一、什么是循环依赖

循环依赖即循环引用,形成闭环。比如,A 依赖 B,B 又依赖 A,形成了循环依赖;或者 A 依赖 B,B 依赖 C,C 又依赖 A,形成了循环依赖;更或者是自己依赖自己。如图:

这不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结条件。Spring 循环依赖场景有:

  1. 构造器的循环依赖
  2. 构造器依赖 + field/setter 依赖(A 的构造器依赖 B,B 的 field/setter 依赖 A)
  3. field 依赖或者 setter 依赖

具体情况如下:
1️⃣A 的构造方法中依赖 B 的实例对象,同时 B 的构造方法中依赖 A 的实例对象。(无法解决)
2️⃣A 的构造方法中依赖 B 的实例对象,同时 B 的某个 field/setter 需要 A 的实例对象,以及反之。(可以解决)
3️⃣A 的某个 field/setter 依赖 B 的实例对象,同时 B 的某个 field/setter 依赖 A 的实例对象,以及反之。(可以解决)

二、Spring 三大循环依赖

1️⃣构造器注入循环依赖【不能解决】

表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException表示循环依赖。

@Service
public class A {
    public A(B b) {
    }
}
@Service
public class B {
    public B(A a) {
    }
}

Spring 容器会将每一个正在创建的 Bean 标识符放在一个“当前创建 Bean 池”中,Bean 标识符在创建过程中将一直保持在这个池中,因此如果在创建 Bean 过程中发现自己已经在“当前创建 Bean 池”里时将抛出BeanCurrentlyInCreationException表示循环依赖;而对于创建完毕的 Bean 将从“当前创建 Bean 池”中清除掉。执行结果报错信息为:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:  
    Error creating bean with name 'a': Requested bean is currently in creation:
Is there an unresolvable circular reference? 

根本原因:Spring 解决循环依赖依靠的是 Bean 的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。而构造器表示已经完成实例化,所以构造器的循环依赖无法解决。

2️⃣Singleton Pattern field 属性注入循环依赖【可以解决】

@Service
public class A {
    @Autowired
    private B b;
}
 
@Service
public class B {
    @Autowired
    private A a;
}

结果:项目启动成功,能够正常工作。

备注:setter 方法注入方式原理同字段注入方式类似。

3️⃣prototype 模式 field 属性注入循环依赖【不能解决】

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class A {
    @Autowired
    private B b;
}
 
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class B {
    @Autowired
    private A a;
}

对于prototype 作用域的 bean,Spring 容器无法完成依赖注入,因为 Spring 容器不缓存 prototype 作用域的 bean,因此无法提前暴露一个创建中的 bean。

scope="prototype"意思是每次请求都会创建一个实例对象。两者的区别是:有状态的 bean 都使用 Prototype 作用域,无状态的一般都使用 singleton 单例作用域。

因此本例中启动时是不会报错的(因为非单例 Bean 默认不会初始化,而是使用时才会初始化),所以需要手动 getBean() 或者在一个单例 Bean 内 @Autowired 一下它即可:

// 在单例Bean内注入
    @Autowired
    private A a;

打印结果:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:  
    Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference? 

三、怎么检测是否存在循环依赖

检测循环依赖相对比较容易,Bean 在创建的时候可以给该 Bean 打标,如果递归调用回来发现正在创建中的话,说明循环依赖了。

四、Spring 是如果解决循环依赖的

Spring 通过三级缓存加上“提前曝光”机制,配合 Java 的对象引用原理,比较完美地解决了某些情况下的循环依赖问题。

  1. A 首先完成了初始化的第一步,并且将自己提前曝光到 singletonFactories 中。此时进行初始化的第二步,发现自己依赖对象 B,就尝试去 get(B),发现 B 还没有被 create,所以走 create 流程。
  2. B 在初始化第一步的时候发现自己依赖了对象 A,于是尝试 get(A),由于 A 通过 ObjectFactory 将自己提前曝光了,所以 B 能够通过 ObjectFactory.getObject 拿到 A 对象。
  3. B 拿到 A 对象后顺利完成了初始化阶段 1、2、3,完全初始化之后将自己放入到一级缓存 singletonObjects 中。此时返回 A 中,A 拿到 B 的对象顺利完成自己的初始化阶段 2、3,最终 A 也完成了初始化。
【Spring】Spring 解决循环依赖的 3 种方式 原文:http://www.javastack.cn/article/2020/spring-cycle-depends-on-three-ways/ 循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错。 下面说一下Spring是如果解决循环依赖的。 第一种:构造器参数循环依赖 Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中。 因此如果 阅读详情

相关推荐

RealSense D455的标定并运行VINS-FUSION

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

qq_40186909的博客 2万+

Spring中的循环依赖

目录一、什么是循环依赖?二、Bean的生命周期2.1 Spring Bean 的生命周期2.2 Bean 的生成步骤三、三级缓存3.1三个缓存分别有什么作用四、思路分析4.1 为什么 Spring 中还需要 singletonFactories 呢?五、Spring解决了哪种情况下的循环依赖5.1 ObjectFactory六、getEarlyBeanReference方法七、总结 一、什么是循环依赖? 例如,就是A对象依赖了B对象,B对象依赖了A对象。 // A依赖了B class A{ pub

SuZhan0711 3万+

TruckSim与Simulink联合仿真中的车轮转角精确控制策略

本文深入探讨了TruckSim与Simulink联合仿真中实现车轮转角精确控制的关键策略。针对多轴车辆路径跟踪时转角指令失灵的常见问题,核心在于正确配置TruckSim转向轴的外部输入模式(Advanced Settings),并确保仿真接口的稳定搭建。文章详细解析了从单轴到多轴协同转向的配置方法,并提供了提升MPC路径跟踪精度的实战技巧与调试经验。

weixin_29035147的博客 367

【Spring】Spring的循环依赖以及解决方案

​ Spring循环依赖指的是两个或多个Bean之间相互依赖,形成一个环状依赖的情况。通俗的说,就是A依赖B,B依赖C,C依赖A,这样就形成了一个循环依赖的环。​ Spring循环依赖通常会导致Bean无法正确地被实例化,从而导致应用程序无法正常启动或者出现异常。因此,Spring循环依赖是一种需要尽量避免的情况。

长夜烛火的博客 7995

用Omniverse Kit开发第一个USD插件:从环境配置到实战案例(Python 3.7版)

本文详细介绍了如何使用NVIDIA Omniverse Kit和Python 3.7开发第一个USD插件,涵盖从环境配置到实战案例的全过程。通过创建可实时同步材质属性的USD插件,开发者可以快速掌握Omniverse开发框架,提升3D内容创作效率。

x8y9z0的博客 585

产品经理如何运用AI提升工作效率

AI技术的应用为产品经理的工作流程带来了显著的效率提升。从需求收集到产品上线,AI可以在多个阶段提供智能化支持,帮助产品经理更好地理解用户需求、优化产品设计、提高开发和测试效率。在未来,随着AI技术的不断发展,产品经理将能够更加高效地管理产品生命周期,为用户提供更优质的产品体验。应用 | AI + 千行百业欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机视觉的精彩内容。

不想宅的冷同学 1335

Spring 循环依赖解决方案

循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如A引用B,B引用C,C引用A,则它们最终反映为一个环。结论先行:1.构造器循环依赖----初始化失败2.field属性注入循环依赖----初始化成功3.field属性注入循环依赖(prototype)----初始化失败现象总结:同样对于循环依赖的场景,构造器注入和prototype类型的属性注入都会初始化Bean失败。因为@Service默认是单例的,所以单例的属性注入是可以成功的。

sinat_34814635的博客 2万+

①电子产品拆解分析-暖手宝

电子产品拆解分析-暖手宝 ①按键三档调温暖手; ②长按进入氛围呼吸灯; ③安卓接口充电以及支持USB输出;

a6662580的博客 5289

Spring 循环依赖 (Circular Dependency)

摘要:本文探讨了SpringBoot中的循环依赖问题及其解决方案。循环依赖指多个Bean相互引用形成闭环,常见于构造器注入和字段注入场景,在SpringBoot2.6+版本中会导致启动失败。最佳解决方案是解耦设计,推荐使用静态工具类或提取公共Service来打破循环依赖关系。次优方案包括使用@Lazy延迟加载或修改配置允许循环依赖(不推荐)。文章重点分析了MyBatis-Plus的Db静态工具为何能避免循环依赖,因其在运行时而非启动时执行查询,实现弱耦合。建议开发者优先考虑架构优化,避免使用循环依赖设计模式

2301_81138380的博客 794

液态神经网络(LNN):打破AI“静态快照”的连续动力学革命---AI大模型系统从零开始0029

MIT研究团队受秀丽隐杆线虫神经系统的启发,开发出革命性的液态神经网络(LNN)。该技术通过连续微分方程建模神经元动态,实现输入响应速度的自适应调节,解决了传统AI模型静态化、高能耗和低解释性的痛点。LNN具有三大突破性优势:仅需少量神经元(如20个)即可完成复杂任务;能处理非均匀时序数据;在自动驾驶、医疗监测等领域展现出卓越的适应性和鲁棒性。这项将生物智能与数学建模完美融合的技术,有望成为下一代AI的核心架构,目前已在无人机导航等场景验证了其高效性,被预测为2026年最具潜力的AI突破方向。

添柴程序猿的专栏 370

FineReport 动态列切换统计维度

目标: 自己选择统计维度进行数据的汇总统计数据集参数实现动态列。

Davina_yu的博客 1053

Spring 在启动时检测到循环依赖(circular dependency)

Spring启动时抛出BeanCurrentlyInCreationException异常,表明asyncUserDetailService与asyncCompanyService存在循环依赖问题。异常指出原始版本的Bean被注入,而非最终代理版本,可能导致运行时不一致。建议解决方案是在AsyncCompanyService中使用@Lazy注解延迟加载AsyncUserDetailService,以打破循环依赖。这种方法是解决Spring循环依赖问题的推荐方案之一。

m0_58680865的博客 447

VIVADO IP核之FIR插值器多相滤波仿真

网络上有许多文章介绍FIR低通滤波器的使用,包括仿真。关于FIR低通滤波器的使用,我之前的文章已经介绍过了,本文将继续深入介绍FIR插值器多相滤波的使用方法,并将FIR插值多相滤波的结果与MATLAB仿真计算的结果比较,验证了FIR插值器多相滤波使用正确。

m0_66360845的博客 3380

【终极解决】Spring 循环依赖报错 Circular dependency?3 种方案 + 避坑指南!

Spring 循环依赖报错 Circular dependency?3 种方案 + 避坑指南

大家好,我是一名深耕 Java 后端多年的老程序员,目前专注于 SpringBoot / SpringCloud / 微服务 / 分布式 方向开发。 多年企业级项目实战经验,踩过无数线上坑、填过无数架构坑,对 Spring 全家桶、MyBa 326

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Spring:如何解决循环依赖问题?

Spring:如何解决循环依赖问题: https://www.fatalerrors.org/a/spring-how-do-i-solve-the-circular-dependency-problem.html Spring-bean的循环依赖以及解决方式: https://blog.youkuaiyun.com/u010853261/article/details/77940767

xfxuezhang.cn 1万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Spring Bean注入失败合集|3类高频报错+全场景解决方案(附避坑指南)

Spring Bean注入失败合集|3类高频报错+全场景解决方案(附避坑指南)

大家好,我是一名深耕 Java 后端多年的老程序员,目前专注于 SpringBoot / SpringCloud / 微服务 / 分布式 方向开发。 多年企业级项目实战经验,踩过无数线上坑、填过无数架构坑,对 Spring 全家桶、MyBa 387

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Spring中的循环依赖解决方案

1. 什么是循环依赖? 一般场景是一个Bean A依赖Bean B,而Bean B也依赖Bean A. Bean A → Bean B → Bean A 当然我们也可以添加更多的依赖层次,比如: Bean A → Bean B → Bean C → Bean D → Bean E → Bean A 2. Spring中的循环依赖 当Spring上下文在加载所有的bean时,他会尝试按照他们他们关联关系的顺序进行创建。比如,如果不存在循环依赖时,例如: Bean A → Bean B → Bean C

疯一样的女子 1016

如何解决spring循环依赖

Spring在创建Bean时,需要先实例化依赖的Bean。但在循环依赖的情况下,两个Bean都需要对方先创建,导致。当Bean A依赖于Bean B,而Bean B又依赖于Bean A时,就形成了循环依赖。循环依赖通常是代码设计不合理的信号,优先通过重构消除依赖关系。只有在无法避免的情况下,才考虑使用。但这种方法只是掩盖了问题,并没有真正解决依赖设计的缺陷,可能导致运行时问题。注解会告诉Spring在运行时才注入依赖,而不是在初始化时,从而打破循环。问题,即两个或多个Bean之间相互依赖,形成了一个闭环。

m0_49382941的博客 499

Spring的循环依赖问题

问题提出 Spring中代码-产生循环依赖问题 @Component class A{ private B b; public A(B b) { this.b = b; } } @Component class B{ private A a; public B(A a) { this.a = a; } } 报错 Error starting ApplicationContext. To display the c

caijibaindashen的博客 466

Spring源码之 Bean 的循环依赖

循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示:代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢?可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 重写 customizeBeanFact

java_beautiful的博客 320

Spring源码分析之IOC容器解决循环依赖问题

看现象 maven依赖 我们只测试IOC容器,因此只需要引入spring-context即可 <dependencies> <!--测试框架--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>

xvktdmjg的博客 243

Spring中的循环依赖问题及解决方案

一、循环依赖的概念1.概念循环依赖是指两个或多个Bean相互依赖,形成一个闭环。例如,Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean A。又或者 Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean C,Bean A 依赖于 Bean A。循环依赖一般由构造器注入或Setter注入造成。2.举例例:由构造器注入的循环依赖2.1Java代码2.2XML配置二、解决方案。

weixin_53495571的博客 586

【异常】Application failed to start due to an exception org.springframework.beans.factory.BeanCurrentlyI...

一、 异常信息: 2018-05-17 18:03:22.224 -DEBUG [restartedMain] o.s.b.d.LoggingFailureAnalysisReporter: Application failed to start due to an exception org.springframework.beans.factory.BeanCurr...

weixin_30480651的博客 4692

这个 Spring 循环依赖的坑,今天让我遇见了

点击上方蓝色字体,选择“标星公众号”优质文章,第一时间送达上一篇:这300G的Java资料是我师傅当年给我的,免费分享给大家(已修复)下一篇:昨天分享资料不小心把百度网盘深处的秘密泄露了...

公众号-老炮说Java 284

SpringBoot循环依赖解决

将Bean注入到Spring容器、那么在注入过程中,如遇到这样的问题在将BeanA注入到容器中的过程中:BeanA持有BeanB的引用,BeanB持有BeanC的引用。BeanC持有BeanA的引用、当BeanA注入依赖于BeanC,BeanC又依赖于BeanA。如果确实需要循环依赖,那么可以通过前文提到的方式来处理。容器构造是指在容器启动的时候,依赖关系已经建议好了、那么我们就要去避免容器初始化的时候去建议依赖关系、即我们不要出现BeanA-BeanB-BeanC-BaenA的这种依赖的结构。...

web_15534274656的博客 939

circular dependency

循环依赖是和语言无关的一个设计问题,在各个语言环境下都可能存在循环依赖,甚至引起 stackoverflow,这种大多数是由于不好的设计而导致的,一般来说都可以通过提取公共模块而解决,特定的场景下对应用程序做一定的调整也可以在维持循环依赖的前提下避免栈溢出。   语言机制:   c++   c++ 中的循环类定义引用会导致编译出错,一般的解决方案可以通过提前声明来解决:     ...

{ focus : web } 1518
上一篇: 单例模式(Singleton Pattern)
下一篇: Redis 是单线程的正确理解
JFS_Study
博客等级 码龄6年 363粉丝 359原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值