系列二十、Spring循环依赖问题

一、概述

        循环依赖是指多个bean之间相互依赖,形成了一个闭环。比如A依赖于B、B依赖于C、C依赖于A,形成了一个圈,如:

二、循环依赖案例

2.1、构造方法注入产生循环依赖案例

2.1.1、ServiceA

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 9:14* @Description:*/
@Service
public class ServiceA {private ServiceB serviceB;public ServiceA(ServiceB serviceB) {this.serviceB = serviceB;}
}

2.1.2、ServiceB

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 9:14* @Description:*/
@Service
public class ServiceB {private ServiceA serviceA;public ServiceB(ServiceA serviceA) {this.serviceA = serviceA;}
}

2.1.3、MySpringConfig

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:29* @Description:*/
@Configuration
@ComponentScan(basePackages = {"org.star"})
public class MySpringConfig {}

2.1.4、AopFullAnnotationMainApp

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);ServiceA serviceA = context.getBean("serviceA", ServiceA.class);log.info("serviceA:{}", serviceA);}
}

2.1.5、结论

使用构造方法注入属性会产生循环依赖问题。

2.2、set方法注入不会产生循环依赖案例

2.2.1、ServiceAA

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 9:27* @Description:*/
@Service
public class ServiceAA {@Resourceprivate ServiceBB serviceBB;}

2.2.2、ServiceBB

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 9:27* @Description:*/
@Service
public class ServiceBB {@Resourceprivate ServiceAA serviceAA;}

2.2.3、MySpringConfig(同上)

2.2.4、AopFullAnnotationMainApp

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);ServiceAA serviceAA = context.getBean(ServiceAA.class);log.info("serviceAA:{}", serviceAA);}
}

2.2.5、结论

使用set方法注入属性不会产生循环依赖问题。

2.2.6、注意事项

        默认情况下使用set方法注入属性可以解决循环依赖问题,但是有一个前提,bean是单例的,当把bean设置为多例后,再使用set注入时依然会产生循环依赖问题。

三、Spring解决循环依赖的方法

3.1、三级缓存

        所谓Spring的三级缓存是指Spring内部解决循环依赖问题的三个Map,即 DefaultSingletonBeanRegistry 中定义的三个Map。部分源码如下:

3.2、A、B对象在三级缓存中的迁移过程

第一步:A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B;

第二步:B实例化的时候发现需要A,于是B先查找一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,于是找到A,然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A;

第三步:B顺利完成初始化,并将自己放到一级缓存里面(注意:此时B里面的A依然是创建中的状态),然后接着回来创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。

3.3、断点顺序

# 参考B站尚硅谷周阳老师录制的视频,链接地址如下https://www.bilibili.com/video/BV1Hy4y1B78T?p=39&spm_id_from=pageDriver&vd_source=72ebc194dbfa51ec950a52c25c337f7c

 

3.4、解决循环依赖的步骤

        第一步:Spring创建bean主要分为两个步骤,即:创建原始bean对象 & 填充对象属性和初始化;

        第二步:每次创建bean之前,Spring都会从缓存中查询该bean是否存在,如果缓存中存在,则直接拿来用,如果没有Spring则去创建原始对象并放入三级缓存中,因为是单例,只能有一个;

        第三步:当创建完A的原始对象后(此时A已经在三级缓存中了),接下来为A填充属性,这时候发现A依赖B,接着又去创建B,同样的流程,创建完B的原始对象后,填充属性时发现B又依赖于A,B实例化的时候需要A,于是B先从一级缓存里面查找A,没有找到,接着再查二级缓存,还是没有,再查三级缓存,于是找到了A,然后Spring把三级缓存里面的A放到二级缓存里面,并删除三级缓存里面的A,B顺利完成初始化,并将自己放入到一级缓存里面(注意:此时B里面的属性A依然是创建中的状态),然后接着回来继续为A填充属性,此时B已经创建结束,Spring直接从一级缓存中取出B,为A赋值,完成A的初始化,然后把A自己放入到一级缓存里面,并删除二级缓存里面的A,此时A,B各自完成实例化。

3.5、解决循环依赖的思想

        Spring解决循环依赖靠的是bean的 中间态 这个概念,而这个中间态指的是 已经实例化但是还没有初始化的状态,即:半成品;实例化的过程又是通过构造器完成的,如果A还没有创建出来怎么提前曝光?这也就解释了使用构造方法注入属性为什么无法解决循环依赖的问题。

Spring解决单例bean循环依赖的三个Map(三级缓存):

        # 一级缓存:单例池,存放已经经历了完整生命周期的bean

        private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

        # 二级缓存:存放早期暴露出来的bean对象,此时bean的生命周期尚未结束(属性还未填充完毕)

        private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

        # 三级缓存:存放可以生成bean的工厂

        private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

3.6、详细过程

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

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

相关文章

AntDB数据库,通信行业20年变迁的见证者

2000年至今&#xff0c;通信行业发展已过了20多年。面对通信行业巨大的数据信息&#xff0c;数据库在行业发展中发挥了巨大的作用&#xff0c;AntDB数据库便是其中较为知名的一款数据库。在通信行业快速发展的阶段&#xff0c;打破国外产品与技术垄断是产业发展的重点与难点。面…

处理分类问题的不平衡数据的 5 种技术

一、介绍 分类问题在机器学习领域很常见。正如我们所知&#xff0c;在分类问题中&#xff0c;我们试图通过研究输入数据或预测变量来预测类标签&#xff0c;其中目标或输出变量本质上是分类变量。 如果您已经处理过分类问题&#xff0c;那么您一定遇到过以下情况&#xff1a;其…

HTML5原生视频播放器组件video的videocontrolslist属性详解

HTML5提供了内置的视频播放控件,其中videocontrolslist是其中一个很有用的属性。videocontrolslist属性可以用于告诉浏览器在视频播放过程中应该显示哪些默认的用户界面控件。下面我们将从几个方面来介绍videocontrolslist的详细使用。 一、启用videocontrolslist videocont…

2024重庆大学计算机考研分析

24计算机考研|上岸指南 重庆大学 重庆大学计算机考研招生学院是计算机学院和大数据与软件学院。目前均已出拟录取名单。 重庆大学计算机学院是我国高校最早开展计算机研究的基地之一&#xff0c;1978年和1986年获西南地区首个硕士和博士点&#xff0c;1998年成立计算机学院&a…

单片机学习2——流水灯的实现

#include<reg52.h>sbit LED P1^0; unsigned char i;void main() {while(1){LED 0;for(i0;i<100;i);LED 1;for(i0;i<100;i);} } RST是复位按钮&#xff0c;单击一下之后&#xff0c;程序就会跑到最开始的位置运行。 右侧的按钮是RUN按钮&#xff0c;单击下&…

ShardingSphere-JDBC 入门教程(v4.1.1)

框架介绍 ShardingSphere-JDBC 定位为轻量级 Java 框架&#xff0c;在 Java 的 JDBC 层提供的额外服务。它使用客户端直连数据库&#xff0c;以 jar 包形式提供服务&#xff0c;无需额外部署和依赖&#xff0c;可理解为增强版的 JDBC 驱动&#xff0c;完全兼容 JDBC 和各种 OR…

利用ogr2ogr从PostGIS中导出/导入Tab/Dxf/Geojson等格式数据

ogr2ogr Demo Command 先查看下当前gdal支持的全部格式&#xff0c;部分gdal版本可能不支持PostGIS。 如出现PostgreSQL表名支持。 #全部支持的格式 ogrinfo --formats | sort #AVCBin -vector- (rov): Arc/Info Binary Coverage #AVCE00 -vector- (rov): Arc/Info E00 (ASC…

数据结构——动态规划

动态规划&#xff1a;有很多重叠子问题&#xff0c;每一个状态一定是由上一个状态推导出来的 贪心&#xff1a;没有状态推导&#xff0c;而是从局部直接选最优的 动规五步曲&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 确定递推公式&#xff08;容…

STM32-SPI1控制AD7705(Sigma-Delta-ADC芯片)

STM32-SPI1控制AD7705&#xff08;Sigma-Delta-ADC芯片&#xff09; 原理图手册说明功能方框图引脚功能 片内寄存器通信寄存器&#xff08;RS2、RS1、RS00、0、0&#xff09;设置寄存器时钟寄存器数据寄存器&#xff08;RS2、RS1、RS00、1、1&#xff09;测试寄存器&#xff08…

SAP Smartforms设计

第八章 SMART FORMS设计 要点列表 概览&#xff1b; Form&#xff08;表格&#xff09;&#xff1b; Smart Styles&#xff08;样式&#xff09;&#xff1b; Text Module&#xff08;文本模块&#xff09;&#xff1b; 使用标准表方式打印&#xff1b; 使用模板方式打印…

淼一科技为互联网企业销毁硬盘数据 拆除机房设备

在上海这座繁华的大都市&#xff0c;淼一科技以其专业的服务和卓越的技术&#xff0c;为众多互联网企业提供硬盘数据销毁和机房设备拆除服务。作为业界领先的数据安全解决方案提供商&#xff0c;淼一科技致力于保障客户数据的安全与隐私&#xff0c;为客户创造更高的商业价值。…

leetcode周赛373场

leetcode周赛373场 第三题2948题 评论区的解题思路找到了很好的解法&#xff0c;当时没有想到&#xff0c;给原始数组排序后&#xff0c;分段再给数组位置排序。 class Solution {public int[] lexicographicallySmallestArray(int[] nums, int limit) {int n nums.length;I…

uni-app:心跳机制基础逻辑(定时器方法解决)

思路 1、在登录的时候&#xff0c;定义一个存储当前时间的全局变量&#xff0c;并且开始心跳请求 2、在全局中定义一个定时器&#xff0c;该定时器每秒都会执行一次&#xff0c;并获取当前的时间 3、将定时器每秒的获取的当前时间和全局变量获取的时间进行比较 4、指定一个…

网络运维与网络安全 学习笔记2023.11.27

网络运维与网络安全 学习笔记 第二十八天 今日目标 OSPF基本原理、OSPF单区域配置、OSPF多区域配置 特殊区域之Stub、特殊区域之NSSA OSPF基本原理 项目背景 随着企业的发展&#xff0c;网络的规模越来越大&#xff0c;网段的数量越来越多&#xff0c;公司内部的路由器的…

Windows系统下搭建PXE Server

在给一台服务器初始安装OS时一般有以下几种方式&#xff1a; 1、通过BMC挂载iso镜像来安装&#xff1b; 2、通过U盘启动来安装&#xff1b; 3、通过网络启动来安装&#xff1b; 方式1和方式2只能一台一台地进行&#xff0c;且需要有键盘和显示器&#xff0c;效率低下&#xff…

在vue页面中添加组件到底有多方便

修改vue写的前端页面到底有多方便&#xff1f;如果熟练的话&#xff0c;出乎你想象的快。 原来的页面&#xff1a;/admin/stock 原来的文件地址&#xff1a;src\views\admin\stock\Stock.vue 另一个页面有个入库功能&#xff0c;需要转移到上面的页面中&#xff1a; 路径&…

基于C#实现块状链表

在数据结构的世界里&#xff0c;我们会认识各种各样的数据结构&#xff0c;每一种数据结构都能解决相应领域的问题&#xff0c;当然每个数据结构&#xff0c;有他的优点&#xff0c;必然就有它的缺点&#xff0c;那么如何创造一种数据结构来将某两种数据结构进行扬长避短&#…

Java代码生成器,一键在线生成,支持自定义模板

【Java代码生成神器】自动化生成Java实体类、代码、增删改查功能&#xff01;点击访问 推荐一个自己每天都在用的Java代码生成器&#xff01;这个网站支持在线生成Java代码&#xff0c;包含完整的Controller\Service\Entity\Dao代码&#xff0c;完整的增删改查功能&#xff01…

金鸣表格文字识别客户端输出项该如何选择?

智能布局&#xff1a;根据提交的图片自动设置输出的打印纸张大小和方向&#xff0c;其中表格识别默认为A4纵向&#xff0c;勾选“合并”可将N张图片批量识别成一个文件、一个表。 表格识别&#xff1a; excel&#xff1a;输出可编辑的excel。 word&#xff1a;输出可编辑的w…

10G以太网接口的FPGA实现,你需要的都在这里

参考链接&#xff1a;10G以太网接口的FPGA实现&#xff0c;你需要的都在这里 - 知乎