Spring循环依赖详解

一、什么是循环依赖

        在Spring框架中,循环依赖是指两个或更多的Bean相互间直接或间接地依赖对方的情况。这种依赖关系可能导致Bean的实例化过程中出现问题,但Spring通过其内部的处理机制能够解决某些类型的循环依赖。

        简单的说就是A依赖B,B依赖C,C依赖A这样就构成了循环依赖。

二、循环依赖的3种情况

1. 构造器循环依赖

        当Bean通过构造器参数注入其他Bean,并且存在循环依赖时,Spring无法解决这种依赖。这是因为Bean的实例化需要依赖于尚未创建完成的其他Bean,从而导致死锁。

public class StudentA {private final StudentB studentB;public StudentA(StudentB studentB) {this.studentB = studentB;}
}public class StudentB {private final StudentA studentA ;public StudentB(StudentA studentA) {this.studentA = studentA;}
}

2. 原型(prototype)模式下的setter注入循环依赖

        循环依赖双方 scope 都是 prototype 的话,也会循环依赖失败,代码如下:

@Service
@Scope("prototype")
public class AService {@AutowiredBService bService;
}@Service
@Scope("prototype")
public class BService {@AutowiredAService aService;
}

        两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。

        scope 为 prototype 意思就是每次请求都会创建一个新的实例对象,不用缓存里的。那么 AService 需要 BService,所以就去现场创建 BService,结果 BService 又需要 AService,继续现场创建,AService 又需要 BService...,所以最终就陷入到死循环了。

报错信息:

3. 单例(singleton)模式下的setter注入循环依赖

        以上两种的循环依赖Spring并没有解决,需要开发者进行相应的设计调整或使用其他的依赖注入策略。但是单例模式下的setter注入循环依赖,Spring能够解决。

Spring的Bean实例化过程中会使用一个三级缓存机制:

  • 一级缓存(singletonObjects):存储已经完全初始化的单例Bean。
  • 二级缓存(earlySingletonObjects):存储尚未完全初始化的Bean,即已经实例化但尚未完成属性填充的Bean。
  • 三级缓存(singletonFactories):存储Bean的工厂对象,该对象可以创建Bean的实例并将其放置在二级缓存中。

当Spring检测到循环依赖时,它不会等待所有依赖都初始化完成,而是将Bean的工厂对象提前暴露给其他正在创建的Bean。这样,即使Bean尚未完成初始化,其他Bean也能引用它,从而打破了死锁状态。

懒加载解决循环依赖:

        在某些情况下,可以使用@Lazy注解来延迟Bean的初始化,从而避免循环依赖

public class BeanA {
@Autowired
@Lazy
private BeanB beanB;
}

public class BeanB {
@Autowired
private BeanA beanA;
}

三、三级缓存

        Spring能够轻松的解决属性的循环依赖正式用到了三级缓存,在AbstractBeanFactory中有详细的注释。

  • 一级缓存:singletonObjects,存放完全实例化属性赋值完成的Bean,直接可以使用。
  • 二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean
  • 三级缓存:singletonFactories,三级缓存,存放实例化完成的Bean工厂。
1.getSingleton(beanName):源码如下:

从源码可以得知,doGetBean最初是查询缓存,一二三级缓存全部查询,如果三级缓存存在则将Bean早期引用存放在二级缓存中并移除三级缓存。(升级为二级缓存)

2. addSingletonFactory:源码如下

从源码得知,Bean在实例化完成之后会直接将未装配的Bean工厂存放在三级缓存中,并且移除二级缓存

3. addSingleton:源码如下:

Bean添加到一级缓存,移除二三级缓存。

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

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

相关文章

数据结构——堆(C语言版)

树 树的概念: 树(Tree)是一种抽象数据结构,它由节点(node)的集合组成,这些节点通过边相连,把 节点集合按照逻辑顺序抽象成图像,看起来就像一个倒挂着的树,也…

通过 C# 写入数据到Excel表格

Excel 是一款广泛应用于数据处理、分析和报告制作的电子表格软件。在商业、学术和日常生活中,Excel 的使用极为普遍。本文将详细介绍如何使用免费.NET库将数据写入到 Excel 中,包括文本、数值、数组、和DataTable数据的输入。 文章目录 C# 在Excel单元格…

尝试一文带你理解 --- 进程的控制

序言 在前两篇文章中都使用到了名为 fork 的函数,我们简单地介绍了他可以创建一个子进程。所以,在这篇文章中,除了进程的创建,还会介绍进程的退出,进程的等待,进程的替换等内容,帮助大家更好地去…

深度解析Linux-C——结构体(初始化,结构体数组,结构体大小,位段操作,联合体,内存对齐,C的预处理,宏和带参宏,条件编译)

目录 结构体的三种初始化 结构体的两种引用 结构体数组 结构体大小 结构体实现位段操作 联合体 内存对齐 C的预处理 带参宏 条件编译 结构体的三种初始化 定义如下结构体 struct student {char name[100]; int age; float height; } ; 1、定义变量时初始化 s…

Android APK混淆处理方案分析

这里写目录标题 一、前言1.1 相关工具二、Apk 分析2.1 apk 解压文件2.2 apk 签名信息2.3 apk AndroidManifest.xml2.4 apk code三、Apk 处理3.1 添加垃圾文件3.2 AndroidManifest.xml 处理3.3 dex 混淆处理3.4 zipalign对齐3.5 apk 重新签名3.6 apk 安装测试四、总结一、前言 提…

LoRaWAN网络中的chirpstack

目录 一、chirpstack介绍 二、网关与chirpstack之间的通信 三、NS与AS之间的通信 1、Protobuf 2、gRPC 一、chirpstack介绍 ChirpStack 是一个开源的 LoRaWAN 网络服务器,可用于 设置私有或公共 LoRaWAN 网络。ChirpStack 提供了一个 Web 界面 用于管理网关、设…

ELK安装(Elasticsearch+Logstash+Kibana+Filebeat)

一、简介 1.1、软件简介 ELK其实是Elasticsearch,Logstash 和 Kibana三个产品的首字母缩写,这三款都是开源产品。 1.1.1、Elasticsearch简介 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析…

【Linux】文件系统|CHS寻址|LBA逻辑块|文件索引|inode|Date block|inodeBitmap|blockBitmap

前言 一个进程通过文件描述符标识一个打开的文件,进程拿着文件描述符可以在内核中找到目标文件进行读写等操作。这是打开的文件,而没有被打开的文件存储在磁盘中,是如何管理的?操作系统在偌大的磁盘中如何找到想要的文件并打开的…

Redis从入门到超神-(十二)Redis监听Key的过期事件

前言 试想一个业务场景,订单超过30分钟未支付需要做自动关单处理,修改订单状态,库存回退等,你怎么实现?方案一:可以使用定时任务扫表,通过支付状态和下单时间来判断是否支付过期。但是这样的方案是非常消耗…

Modbus转BACnet/IP网关BA100-配硬件说明

在现代自动化系统中,不同设备和系统之间的通信至关重要,Modbus和BACnet/IP协议虽然各有优势,但它们之间的直接通信存在障碍。钡铼Modbus转BACnet/IP网关作为连接这两种协议的桥梁,允许不同系统之间的无缝数据交换。 一、Modbus转…

如何避免蓝屏?轻量部署,安全和业务连续性才能两不误

自19日起,因CrowdStrike软件更新的错误配置而导致的“微软全球蓝屏”,影响依然在持续。这场被称为“史上最大规模的IT故障”,由于所涉全球企业太多,专家估计“蓝屏”电脑全部恢复正常仍需时日。 尽管 CEO 乔治 库尔茨&#xff08…

C++自定义字典树结构

代码 #include <iostream> using namespace std;class TrieNode { public:char data;TrieNode* children[26];bool isTerminal;TrieNode(char ch){data ch;for (int i 0; i < 26; i){children[i] NULL;}isTerminal false;} }; class Trie { public:TrieNode* ro…

matlab仿真 模拟调制(下)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第五章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all ts0.001; t0:ts:10-ts; fs1/ts; dffs/length(t); msgrandi([-3 3],100,1); msg1msg*ones(1,fs/10); msg2reshape(ms…

for循环计算1~100之间3的倍数的数字之和

你要计算1~100之间的数字先得打印出来1~100之间的数字然后在判断是不是3的倍数然后在打印出数字&#xff0c;代码如下 #include<stdio.h> int main() {int i 0;for (i 1; i < 100; i){if (i % 3 0){printf("%d ", i);}}return 0; }

Java漏洞复现(ctfshow279-297)strust 漏洞复现及原理解释

Java漏洞复现 Strust原理 JavaEE--------Struts2框架-CSDN博客 Web279 struts2漏洞 S2-001是当用户提交表单数据且验证失败时&#xff0c;服务器使用OGNL表达式解析用户先前提交的参数值&#xff0c;%{value}并重新填充相应的表单数据。 这里的%{value}简单理解就是和flask的…

7月22日学习笔记 文件共享服务nfs,SAMBA文件共享与DNS域名服务

任务背景 由于业务驱动&#xff0c;为了提⾼⽤户的访问效率&#xff0c;现需要将原有web服务器上的静态资源 ⽂件分离出来&#xff0c;单独保存到⼀台⽂件服务器上。 任务要求 1. ⼀台应⽤服务器web-server部署apache&#xff0c;静态⽹⻚资源存放在另外⼀台NFS服 务器上 …

Vue3相比于Vue2进行了哪些更新

1、响应式原理 vue2 vue2中采用 defineProperty 来劫持整个对象&#xff0c;然后进行深度遍历所有属性&#xff0c;给每个属性添加getter和setter&#xff0c;结合发布订阅模式实现响应式。 存在的问题&#xff1a; 检测不到对象属性的添加和删除数组API方法无法监听到需要对…

监控Windows文件夹下面的文件(C#和C++实现)

最近在做虚拟打印机时&#xff0c;需要实时监控打印文件的到达&#xff0c;并移动文件到另外的位置。一开始我使用了线程&#xff0c;在线程里去检测新文件的到达。实际上Windows提供了一个文件监控接口函数ReadDIrectoryChangesW。这个函数可以对所有文件操作进行监控。 ReadD…

JS+H5在线文心AI聊天(第三方接口)

源码在最后面 调用的不是文心官方接口 可以正常聊天 有打字动画 效果图 源代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-s…

目标检测自顶向下入门

最近在学习Yolo和OpenCV这些计算机视觉的相关领域&#xff0c;把深度学习啃了个大概&#xff0c;准备着手学习一下Yolov5&#xff0c;趁着这个机会入门一下目标检测这个领域&#xff0c;也算是自顶向下地学习一遍吧。 目标检测 什么是目标检测 物体识别&#xff08;Object de…