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

getSingleton(String beanName)

在Spring的doGetBean()方法中的第一次调用getSingleton方法(也就是getSingleton(String beanName)方法)中,反映了Spring中针对循环依赖的解决思想。

当Spring容器初始化时,对于每一个声明为单例的Bean,Spring都会创建一个对应的ObjectFactory并将其存储在singletonFactories映射中。在这个映射中,beanName作为键,对应的ObjectFactory作为值。因此,当需要获取一个单例Bean的实例时,Spring会首先尝试从singletonObjects映射中获取该实例。如果该实例不存在,并且允许早期引用(allowEarlyReference为true),那么Spring会从earlySingletonObjects映射中获取该实例。如果仍不存在,Spring会从singletonFactories映射中获取对应的ObjectFactory,并调用其getObject()方法来创建并返回该Bean的实例。

这个ObjectFactory和earlySingletonObjects就是解决循环依赖问题的关键!

// Bean实例的缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 从缓存中获取Object singletonObject = this.singletonObjects.get(beanName);// 若缓存内不存在且当前正在创建该单例Beanif (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 从早期缓存中获取单例实例singletonObject = this.earlySingletonObjects.get(beanName);// 若早期缓存中不存在且允许早期引用if (singletonObject == null && allowEarlyReference) {// 获取对应的ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 获取该ObjectFactory对应的实例singletonObject = singletonFactory.getObject();// 填充早期缓存this.earlySingletonObjects.put(beanName, singletonObject);// 删除对应的ObjectFactorythis.singletonFactories.remove(beanName);}}}}return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

在这个getSingleton方法中,Spring使用了几个关键的策略和技术来解决循环依赖的问题。

  1. 三级缓存机制:Spring使用了三级缓存机制,即singletonObjectsearlySingletonObjectssingletonFactories。这三个Map结构用于存储不同阶段的单例Bean。
    • singletonObjects:存储完全初始化好的Bean。
    • earlySingletonObjects:存储Bean的早期引用,也就是说Bean已经被实例化了,但是还没进行属性填充和初始化方法。
    • singletonFactories:存储创建Bean的工厂对象,也就是ObjectFactory。
  2. 检查当前Bean是否在创建中isSingletonCurrentlyInCreation(beanName)方法用于检查当前Bean是否正在被创建。如果返回true,说明存在循环依赖。
  3. 同步代码块:当检测到循环依赖时,Spring使用了同步代码块来确保线程安全。这避免了在多线程环境下可能出现的并发问题。
  4. singletonFactories中获取ObjectFactory:如果当前Bean正在创建中并且允许早期引用,Spring会从singletonFactories中获取该Bean的ObjectFactory。
  5. 通过ObjectFactory创建Bean的早期引用:然后调用ObjectFactory的getObject()方法来创建一个该Bean的早期引用,并将其放入earlySingletonObjects缓存中。同时从singletonFactories中移除该ObjectFactory,确保每个Bean只被创建一次。
  6. 解决循环依赖:通过这种机制,即使Bean还没有完全初始化完成,其他依赖于它的Bean也可以通过earlySingletonObjects获取到它的早期引用,从而解决了循环依赖的问题。

总结来说,Spring通过三级缓存机制、同步代码块和ObjectFactory的配合使用,巧妙地解决了循环依赖的问题。这确保了每个Bean只被创建一次,并且在解决依赖关系时线程安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/192048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验8 图的操作

0x01 实验目的 掌握无向图的创建、遍历方法。 0x02 实验内容 创建图类&#xff0c;存储结构使用邻接矩阵。输入图的节点数n(小于10个)、边数m&#xff0c;节点分别用1-n代表。采用“起始节点&#xff0c;终止节点&#xff0c;权值”输入图的m条边&#xff0c;创建图。输出从…

XIAO ESP32S3之SenseCraft 模型助手部署

sipeed教程&#xff1a;SenseCraft 模型助手部署 | Seeed Studio Wiki 一、安装ESP-IDF 鉴于我的电脑之前安装过esp-idf v4.3版本&#xff0c;而ESP32-S3需要v4.4及以上版本才支持&#xff0c;所以将esp-idf更新到最新5.1版本。 1、启动mingw32.exe应用 2、进入esp-idf目录 …

重要通知丨 JumpServer 开源堡垒机 V2 社区版即将停止维护

尊敬的 JumpServer 开源堡垒机用户&#xff0c;您好&#xff01; 根据《关于 JumpServer 开源堡垒机 V2 版本产品生命周期的相关说明》&#xff0c;JumpServer 开源堡垒机 V2 版本&#xff08;社区版&#xff09;将于 2023 年 12 月 31 日停止维护支持。 在过去的两年多时间里…

跟着GPT学习shell脚本,理论与实践相结合的学习计划。

学习计划&#xff1a;初学者到高手 第1-2周&#xff1a;基础入门 目标&#xff1a;了解Shell脚本的基本概念&#xff0c;掌握基础命令。内容&#xff1a; Shell脚本是什么&#xff0c;为什么使用Shell脚本。基本的Shell命令&#xff08;如ls, cd, mkdir, rm等&#xff09;。简…

封装hook函数【便于复用】

目录 一般函数封装封装hook函数 一般函数封装 普通的删除逻辑封装函数—子组件点击删除-通过 defineEmits 通知父组件&#xff08;自定义事件&#xff09;进行删除 const deleteLoading ref(false) const emits defineEmits<{(e: click-delete, id: string): void }>()…

二叉树的层序遍历(广度搜索法) Python

思路&#xff1a; 层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树 需要借用一个辅助数据结构即队列来实现&#xff0c;队列先进先出&#xff0c;符合一层一层遍历的逻辑&#xff0c;而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。 而这种层序遍历方式就是…

ELK配置记录

1. filebeat.yml配置 启动命令&#xff1a; ./filebeat -e -c filebeat.yml # 输入 filebeat.inputs: - type: logenabled: truepaths:- /soft/log/base.*#跨行日志正则&#xff0c;从有时间的开始&#xff0c;到下一个时间之前结束multiline.pattern: ^\[[0-9]{4}-[0-9]{2}…

Python数据类型字典分析

文章目录 1. 创建字典1.1 创建空字典1.2 创建非空字典 2. 新增字典元素2.1 thisdict[new_key] new_value2.2 update 方法 3. 删除字典元素4. 查找字典元素4.1 in 和 in not 操作符4.2 get 方法4.3 thisdict[key] 5. 修改字典元素6. 遍历字典元素6.1 for 循环遍历6.2 keys 方法…

使用纯js码2个实用功能banner图标切换和表格制作

“I can accept failure, but I cant acceptnot trying.”—— by Michael Jordan    “我可以接受失败&#xff0c;但我不能接受放弃。” ——迈克尔•乔丹   banner图标切换 js原生&#xff1a;图片地址你们自己设置位置&#xff0c;相对位置或者绝对位置即可 <!DOCTY…

【CTA认证】Android8实现android6以下的应用运行时也要申请权限

需求 CTA入网认证&#xff0c;要求低版本比如Android6以下的应用&#xff0c;运行时&#xff0c;也需要有运行时权限(Runtime Permission)功能&#xff0c;不能默认就取到权限&#xff0c;必须人工在设置中打开才可。 环境 Android 8 实现 frameworks 修改思路是所有APP都…

蓝桥杯物联网竞赛_STM32L071_6_RTC显示

作用&#xff1a; RTC在STM32微控制器中通常由一个独立的低功耗晶振和相关的寄存器组成。它可以独立于主处理器运行&#xff0c;即使在系统电源关闭的情况下(需要备用纽扣电池)&#xff0c;也能继续计时和记录日期。注意&#xff1a;RTC是芯片内部的功能&#xff0c;并没有和G…

Android跨进程通信,RPC,IPC

文章目录 Android跨进程通信&#xff0c;RPC&#xff0c;IPC1.IPC原理2.RPC原理2.RPC原理 Android跨进程通信&#xff0c;RPC&#xff0c;IPC RPC&#xff08;基于IPC实现&#xff09; Android binder就是一个RPC框架&#xff0c;在已经启动的一个进程a中&#xff0c;访问到进…

Eaxyx 让圆球跟随鼠标移动

如果出现2023&#xff0c;代表配置成功: 进入Eaxy官方网站&#xff0c;点击文档&#xff1a; 选择 函数->绘图函数->initgraph: 可以看见initgraph&#xff08;&#xff09;函数有如下三个参数: 现在我们想生成一个1280*720大小的窗口&#xff1a; 我们需写如下代码: 但…

AIGC: 关于ChatGPT中的核心API调用示例

Open AI 的 api 调用示例 API的调用的文档&#xff1a;https://platform.openai.com/docs/api-reference/introductionChatGPT官方提供了 Python版的包 和 Nodejs版的包 $pip install openai$npm install openai 我们使用 python3.8版本来安装: $sudo python3.8 -m pip instal…

数据结构算法-冒泡排序算法

引言 虽然选择排序好用 &#xff0c;但有点问题 也就是频繁找最大值下标 放到 未排序的后面 因为每次需要扫描整个未排序序列&#xff0c;找到最大值或最小值的下标&#xff0c;并将其交换到未排序序列的最后一个位置。这样做的问题在于&#xff0c;在后面的迭代中&#xff0c…

C# WPF上位机开发(计算器界面设计)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 c# wpf最大的优势就是开发业务软件比较快、效率比较高。一般来说&#xff0c;它的界面和逻辑部分可以同时开发。界面的部分用xaml编写即可&#xf…

Spring Framework详解

学习目标 能够说出Spring的体系结构 能够编写IOC入门案例 能够编写DI入门案例 能够配置setter方式注入属性值 能够配置构造方式注入属性值 能够理解什么是自动装配 一、Spring简介 1 Spring课程介绍 问题导入 我们为什么要学习Spring框架&#xff1f; 1.1 为什么要学 Spri…

Nat. Mach. Intell. | 预测人工智能的未来:在指数级增长的知识网络中使用基于机器学习的链接预测

今天为大家介绍的是来自Mario Krenn团队的一篇论文。一个能够通过从科学文献中获取洞见来建议新的个性化研究方向和想法的工具&#xff0c;可以加速科学的进步。一个可能受益于这种工具的领域是人工智能&#xff08;AI&#xff09;研究&#xff0c;近年来科学出版物的数量呈指数…

数据结构—两个有序单链表的合并排序算法

viod merge(LNode *A,LNode *B){ LNode *C;//新节点 LNode *p C;//辅助指针 while(A->next !null && B->next !null){ if(A->next->data > B->next->data){//A节点大 p->nextA->next;//A元素插入C AA>next; pp->next; }else{ p->…

如何选择适合的光电传感器与 STM32 微控制器进行接口设计

本文介绍了如何选择适合的光电传感器与 STM32 微控制器进行接口设计的方法。首先我们将介绍一些选择光电传感器的关键因素&#xff0c;包括测量范围、响应时间、分辨率和输出类型。然后我们将介绍如何根据所选传感器的特性进行硬件连接和接口设计。最后&#xff0c;我们将提供示…