【Spring】Spring循环依赖(超重要!!)
目录
什么是循环依赖问题
循环依赖具体是怎么解决的
具体的解决步骤:
通俗实例:
严谨的循环依赖解决图例
为什么使用的是三级缓存,二级缓存不够用吗?
什么是循环依赖问题
Spring的循环依赖是指在Bean之间存在相互依赖关系,形成一个闭环的情况。简单来说,Bean A依赖于Bean B,同时Bean B也依赖于Bean A,这就构成了循环依赖。
下面是一个示例,展示了Spring中循环依赖的情况:
// Class A
public class A {private B b;public A() {}public void setB(B b) {this.b = b;}public void doSomething() {System.out.println("Class A is doing something.");}
}// Class B
public class B {private A a;public B() {}public void setA(A a) {this.a = a;}public void doSomethingElse() {System.out.println("Class B is doing something else.");}
}
在上述示例中,类A依赖于类B的实例,而类B又依赖于类A的实例。当我们使用Spring容器来创建这两个类的实例时,就会发生循环依赖的情况。
<!-- XML 配置文件 -->
<bean id="a" class="com.example.A"><property name="b" ref="b" />
</bean><bean id="b" class="com.example.B"><property name="a" ref="a" />
</bean>
在上述配置中,我们定义了Bean A和Bean B,并通过属性注入方式使它们相互引用。
如果我们运行以下代码来获取Bean A的实例:
public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");A a = context.getBean(A.class);a.doSomething();
}
在这种情况下,Spring会尝试创建Bean A的实例。但是由于循环依赖,它会先创建一个空的Bean A,并将其放入缓存中。然后,Spring继续创建依赖的Bean B,但因为它也依赖Bean A,Spring会从缓存中获取Bean A的实例,并将其注入到Bean B中。
接下来,Spring回到缓存中,将属性注入到之前创建的Bean A实例中,完成Bean A的初始化。最后,Bean A的完全初始化实例返回给调用方。
循环依赖具体是怎么解决的
Spring使用了三级缓存以及"提前曝光"的机制来解决循环依赖的问题。
具体的解决步骤:
-
创建空对象:当Spring容器发现循环依赖时,会先创建一个空对象作为Bean A或Bean B的临时实例,并将其放入第一级缓存中。
-
属性注入:然后,Spring会继续创建被循环依赖的Bean的其他属性,并将这些属性注入到临时实例中。
-
提前曝光:在注入属性期间,如果发现循环依赖的Bean已经存在于第一级缓存中,Spring会将那个早期的实例提前曝光到第二级缓存中,以供其他需要依赖它的Bean使用。
-
创建完整实例:完成属性注入后,Spring会将临时实例传递给Bean的初始化方法,并执行初始化操作。初始化完成后,循环依赖的Bean就成为一个完整的可用实例了。
-
缓存实例:最后,Spring将这个完整的Bean实例放入第三级缓存中,以供后续使用。
通俗实例:
假设有两个人,小明和小红,他们互相依赖对方来完成一项任务。小明需要小红的帮助才能完成自己的任务,而小红也需要小明的帮助才能完成自己的任务。这就形成了一个循环依赖的情况。
为了解决这个问题,他们采取以下步骤:
-
小明向小红发出请求:小明首先联系小红,告诉她自己需要她的帮助来完成任务。
-
小红创建一个"空的"小明实例:小红收到请求后,会先创建一个空的小明实例,并进行标记,表示这是一个临时的、不完整的实例。
-
小红继续进行自己的任务:在创建小明实例的同时,小红并不会等待小明的实例完成,而是继续进行自己的任务。
-
小明提供帮助:在小红继续进行自己的任务期间,小明得到了小红的帮助,完成了自己的任务。
-
小红注入属性:当小明的任务完成后,小红会将小明实例中需要的属性注入进去,使得小明的实例成为一个完整的、可用的实例。
-
小红完成任务:接着,小红继续进行自己的任务,并顺利完成。
大概就是这样一个流程
严谨的循环依赖解决图例

为什么使用的是三级缓存,二级缓存不够用吗?
假设有两个类 A 和 B,它们相互依赖对方来完成初始化。A 类依赖于 B 类的实例,而 B 类也依赖于 A 类的实例。这种情况下,如果只使用二级缓存,会导致属性注入的顺序错误,从而无法正确解决循环依赖。
具体示例:
- 创建 A 类实例:首先,Spring 会尝试创建 A 类的实例,并将其放入二级缓存中。
- 创建 B 类实例:接下来,Spring 发现 B 类依赖 A 类的实例,于是尝试创建 B 类的实例,并将其放入二级缓存中。
- 属性注入:在属性注入过程中,由于 B 类的实例已经在二级缓存中,Spring 尝试从缓存中获取 B 类的实例,并将其注入到 A 类的实例中。但此时 A 类的实例还没有完全初始化,因此导致注入的 A 类实例不完整。
- 初始化 A 类:接着,Spring 继续初始化 A 类的实例并执行初始化操作,但由于 A 类实例的属性注入不完整,可能导致初始化失败或产生不正确的结果。
- 初始化 B 类:最后,Spring 继续初始化 B 类的实例,但由于 B 类实例依赖 A 类的实例,而 A 类实例又没有正确注入,导致 B 类的实例无法正确初始化。
由于二级缓存只能缓存已经完成初始化的 Bean,不能解决属性注入时的循环依赖问题。
而三级缓存相比二级缓存能够正常应对循环依赖的原因在于它引入了一个"早期曝光"的机制,可以在属性注入之前提前暴露早期实例。
具体来说,在三级缓存中,当检测到循环依赖时,Spring 会首先创建一个早期对象(Early Object),并将其放入三级缓存中。早期对象是一个未完成初始化的对象,其中的属性可能尚未注入完全。
通过三级缓存的机制,能够解决从二级缓存获取实例时属性注入顺序错误的问题。
具体流程:
-
创建 A 类早期对象:首先,Spring 创建 A 类的早期对象,并将其放入三级缓存中。
-
创建 B 类实例:接着,Spring 发现 B 类依赖 A 类的实例,于是尝试创建 B 类的实例,并将其放入二级缓存中。
-
属性注入:在属性注入过程中,Spring 从二级缓存中获取 B 类的实例,并将其注入到 A 类的早期对象中。虽然 A 类的早期对象的属性注入仍不完整,但关键是 B 类实例已经被注入。
-
完成 A 类实例化:接下来,Spring 继续完成 A 类的实例化,并执行初始化操作。由于 B 类实例已经注入,A 类能够正确地访问 B 类的属性。
-
创建 B 类早期对象:当初始化 A 类后,Spring 检测到 B 类也存在循环依赖,于是创建 B 类的早期对象,并将其放入三级缓存中。
-
属性注入:在属性注入过程中,Spring 从三级缓存中获取 B 类的早期对象,并将其注入到 A 类的实例中。这样,A 类实例的属性注入得以完成。
-
完成 B 类实例化:最后,Spring 继续完成 B 类的实例化,并执行初始化操作。由于 A 类实例已经注入,B 类能够正确地访问 A 类的属性。
相关文章:
【Spring】Spring循环依赖(超重要!!)
目录 什么是循环依赖问题 循环依赖具体是怎么解决的 具体的解决步骤: 通俗实例: 严谨的循环依赖解决图例 为什么使用的是三级缓存,二级缓存不够用吗? 什么是循环依赖问题 Spring的循环依赖是指在Bean之间存在相互依赖关…...
数据分析之路应该是就此开启了
咱就是说工作以后,就是重新学习的开始啊。 祝自己顺顺利利。 前路漫漫亦灿灿。 数据分析之路,开启吧。 以下是借鉴网上的学习路线。 这个学习路线图主要分为以下几个部分: 基础知识 :包括数学、统计学和编程语言。这是数据分析的…...
win10如何配置jdk环境变量
1.首先要打开系统环境变量配置的页面。具体操作是:打开开始菜单,找到“此电脑”,然后右键“更多”→“属性”。 2.在弹出的页面,选择“高级系统设置” 3.在弹出的页面,选择“环境变量(N)…”。 …...
pm4py使用指南(非机翻)
目录 1. 日志数据读取及预处理(1)查看case和event数量(2)查看起始事件和结束事件(3)时间戳格式的问题 2. 日志数据过滤3. 流程发现4. 模型转化5. 模型可视化 1. 日志数据读取及预处理 通过 pandas库 读取c…...
ChatGPT帮助提升工作效率和质量:完成时间下降40%,质量评分上升 18%
自ChatGPT去年11月发布以来,人们就开始使用它来协助工作,热心的用户利用它帮助撰写各种内容,从宣传材料到沟通话术再到调研报告。 两名MIT经济学研究生近日在《科学》杂志上发表的一项新研究表明,ChatGPT可能有助于减少员工之…...
第二章 搜索
本篇博文是笔者归纳汇总的AcWing基础课题集,方便读者后期复盘巩固~ PS:本篇文章只给出完整的算法实现,并没有讲解具体的算法思路。如果想看算法思路,可以阅读笔者往期写过的文章(或许会有),也可…...
transform_train.json文件解析
transform_train.json 文件内容解析transform_matrix 文件内容解析 {"camera_angle_x": 0.6911112070083618,"frames": [{"file_path": "./train/r_0","rotation": 0.012566370614359171,"transform_matrix": [[…...
Wlan——锐捷零漫游网络解决方案以及相关配置
目录 零漫游介绍 一代零漫游 二代单频率零漫游 二代双频率零漫游 锐捷零漫游方案总结 锐捷零漫游方案的配置 配置无线信号的信道 开启关闭5G零漫游 查看配置 零漫游介绍 普通的漫游和零漫游的区别 普通漫游 漫游是由一个AP到另一个AP或者一个射频卡到另一个射频卡的漫…...
分布式锁系列之zookeeper分布式锁和mysql分布式锁
目录 介绍 下载安装 基本指令编辑 java集成zookeeper 官方提供版 永久节点 临时节点编辑 永久序列化节点 判断当前节点是否存在 获取当前节点中的数据内容 获取当前节点的子节点 更新节点内容 删除节点 zookeeper实现分布式锁 Mysql实现分布式锁 总结 介绍 ZooK…...
Ubuntu部署PHP7.4
系统版本:Ubuntu22.04 PHP版本: 7.4 Mysql版本:8.0 Nginx版本: 最新 1. 更新系统 首先,确保系统包是最新的: sudo apt update && sudo apt upgrade -y2. 安装 Nginx Nginx 在默认的 Ubuntu 仓库中,因此安装…...
WPF中的数据转换-StringFormat
WPF中的数据转换-StringFormat 前言 字符串格式化。使用该功能可以通过设置Binding.StringFormat属性对文本形式的数据进行转换——例如包含日期和数字的字符串。对于至少一半的格式化任务,字符串格式化是一种便捷的技术。 使用 当设置Binding.StringFormat属性…...
java.lang.UnsupportedOperationException解决方法
java.lang.UnsupportedOperationException解决方法 先放错误信息业务场景报错分析先看报错代码位置进入源码查看至此 真相大白 解决方法总结 先放错误信息 业务场景 已知有学生 张三李四王五赵六 等人 private List<String> nameList Arrays.asList("张三", &…...
docker for window更改到非系统盘的使用记录
1、使用Hyper-v模式的docker安装 2、安装docker for windows后安装目录没办法自己选择,固定在c盘 卸载后通过命令行方式设置软连接方式后重新安装来让其安装到软连接的d盘,解决c盘空间问题 mklink /j "C:\Program Files\Docker" "D:\Pr…...
day 38 | ● 518. 零钱兑换 II ● 377. 组合总和 Ⅳ
518. 零钱兑换 II 这道题就是完全背包问题,因为可以选择的数量是无限的。所以第二层的遍历顺序就是从前往后。 因为是次数问题,递推公式是 的,初值应该设定为dp【0】 1,否则无法进行累加。 func change(amount int, coins []i…...
写得了代码,焊得了板!嵌入式开发工程师必修之代码管理方案(中)
目录 2.2 分仓、权限与依赖问题 2.3 基于 Git 进行多仓管理 Git submodule Git subtree Script/CMake Git-Repo Conan 本文来自 武让 极狐GitLab 高级解决方案架构师 🌟 前一篇文章,作者介绍了嵌入式开发场景的代码管理特点与诉求,以及…...
Interlij IDEA 运行 ruoyi 后端项目。错误: 找不到或无法加载主类 com.ruoyi.auth.RuoYiAuthApplication
错误: 找不到或无法加载主类 com.ruoyi.auth.RuoYiAuthApplication 用了 IDEA运行,参考以下issue删除.idea目录也没有用 (官方文档写是用Eclipse运行) 错误: 找不到或无法加载主类 com.ruoyi.auth.RuoYiAuthApplication Issue #I48N2X 若依/RuoYi-C…...
相机设置报错记录
Camera->SetPosition(0.0, -980, 0.0);Camera->SetFocalPoint(0.0, 0.0, 0.0);Camera->SetViewUp(0.0, 1.0, 0.0);上述代码出现错误提示Resetting view-up since view plane normal is parallel,这个时候是viewup方向与投影方向平行了,而出现的…...
Vue3中搜索表单的二次封装
最近使用Vue3ElementPlus开发项目,从整体上构思组件的封装。能写成组件的内容都进行封装,方便多个地方使用。 受AntDesign的启发,在项目中有搜索表单table分页的地方可以封装为一个组件,只需要对组件传入table的列,组成…...
百度23Q2财报最新发布:营收利润加速增长,AI+生态战略渐显规模
百度集团-SW(9888.HK)Q2财报已于2023/08/22(美东)盘前发布,二季度百度集团整体收入实现341亿元,同比增长15%;归属百度的净利润(non-GAAP)达到80亿元,同比增长44%。营收和利润双双实现大幅增长,超市场预期。其中,百度核…...
一个pdf文件分割成两个
# -- coding: utf-8 --** import PyPDF2 # 打开原始PDF文件 # with open(zhongguojinxiandaishi.pdf, rb) as pdf_file: # pdf_reader PyPDF2.PdfReader(pdf_file) # num_pages len(pdf_reader.pages) # # # 确定分割点(例如,将页面一分为二࿰…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...
