【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) # # # 确定分割点(例如,将页面一分为二࿰…...
用TensorFlow Lite Micro在Arduino上跑个‘Hello World’:从模型部署到LED闪烁的完整流程
在Arduino Nano 33 BLE Sense上部署TinyML模型的实战指南 当微控制器遇上机器学习,TinyML技术正在重新定义边缘计算的边界。本文将带您完成从TensorFlow Lite模型训练到Arduino硬件部署的全流程,通过控制LED亮度直观展示正弦波预测结果,让算…...
别再折腾路由器了!用Go语言给阿里云/腾讯云域名写个DDNS服务(附完整代码)
用Go语言打造高可靠DDNS服务:从阿里云到腾讯云的完整实践 每次重启光猫后,公网IP地址就像捉迷藏一样消失不见——这种烦恼对于需要远程访问家庭NAS或自建服务器的技术爱好者来说再熟悉不过了。市面上的第三方DDNS工具要么功能臃肿,要么存在隐…...
3分钟掌握B站缓存视频转换:m4s-converter让你的视频永久保存
3分钟掌握B站缓存视频转换:m4s-converter让你的视频永久保存 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾经遇到过这样的…...
Equalizer APO完整教程:免费系统级音频均衡器从入门到精通
Equalizer APO完整教程:免费系统级音频均衡器从入门到精通 【免费下载链接】equalizerapo Equalizer APO mirror 项目地址: https://gitcode.com/gh_mirrors/eq/equalizerapo Equalizer APO是一款功能强大的免费开源系统级音频均衡器软件,能够为W…...
ROFL Player终极指南:英雄联盟回放分析工具完整使用教程
ROFL Player终极指南:英雄联盟回放分析工具完整使用教程 【免费下载链接】ROFL-Player (No longer supported) One stop shop utility for viewing League of Legends replays! 项目地址: https://gitcode.com/gh_mirrors/ro/ROFL-Player 还在为英雄联盟回放…...
巧用frp与nginx反向代理,实现安全远程访问内网ESXi管理界面
1. 为什么需要远程访问ESXi管理界面 对于运维人员来说,能够随时随地访问ESXi管理界面是刚需。想象一下,当你正在出差或者在家休息时,突然需要检查虚拟机状态或者处理紧急故障,如果只能跑到机房操作,那简直是噩梦。我遇…...
Windows Cleaner:3步彻底解决C盘爆红问题的终极免费清理工具
Windows Cleaner:3步彻底解决C盘爆红问题的终极免费清理工具 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否曾经打开电脑时被C盘爆红的警告吓到…...
Blender 3MF插件:终极3D打印工作流解决方案
Blender 3MF插件:终极3D打印工作流解决方案 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 在3D打印的世界里,你是否曾为文件格式转换而头疼&…...
41.ShadCN 是什么?它如何和 Tailwind CSS 集成,从而更容易构建可访问且可自定义的 React 组件?
shadcn/ui 不是传统意义上“装一个 npm 包就能用的组件库”。它更像一个组件代码生成/分发方案:你通过 shadcn CLI 把组件的 TypeScript 源码直接拷贝进你的项目目录,组件样式用 Tailwind CSS 写好,组件交互与无障碍能力通常基于 Radix UI pr…...
别再傻傻分不清!舵机、步进、无刷、永磁同步,这四种电机到底怎么选?
电机选型实战指南:舵机、步进、无刷与永磁同步的黄金法则 在机器人关节调试现场,一位工程师盯着反复抖动的机械臂摇头:"早知道该用无刷电机...";创客空间里,几个学生围着一台失控的3D打印机争论:…...
