[Spring] 三级缓存解决循环依赖详解

什么是循环依赖

注册一个bean对象的过程:
Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果原始对象种的某个方法被AOP了,那么要根据原始对象生成一个代理对象 – 把最终生成的代理对象放入单例池(singletonObjects,也叫一级缓存)中,下次getBea你就直接从单例池拿

循环依赖就是在依赖注入的时候相互注入,如

public class AService{
	@Autowired
	private BService bService;
}
public class BService{
	@Autowired
	private AService aService;
}

三级缓存过程

Spring使用了三级缓存的策略来解决循环依赖问题,过程大致如下
创建AService的bean:
AService创建
因为暂时还没有BService,所以创建个BService
BService创建
创建过程中,因为AService已经在三级缓存中出现过,所以会进行以下操作
BService中填充AService
因为BService的属性都已经赋值了,所以BService的初始化就结束了,可以直接放到一级缓存中,完整过程为:
BService实例化过程
此时BService已经实例化完成,那么AService中的依赖就可以进行注入了:
AService实例化第二部分
完整流程图如下:
三级缓存解决循环依赖的完成流程图

简单的源码解析

首先在AbstractAutowireCapabaleBeanFactory类里(我是用ctrl+shift+alt+n找到的)的doCreateBean
先创造了一个bean原始对象,此时还没有依赖注入

		BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        
        Object bean = instanceWrapper.getWrappedInstance();

然后将lambda表达式放入三级缓存中

        if (earlySingletonExposure) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
			//放入三级缓存,这个lambda表达式是为了执行aop生成代理对象用的,如果有aop操作,就会拿到代理对象出来
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

紧接着就是A的依赖填充

	this.populateBean(beanName, mbd, instanceWrapper);

在这个里面会走到一个getSingleton方法,也就是在缓存中找BService

	//allowEarlyReference是是否允许循环依赖
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized(this.singletonObjects) {
                	//一级缓存中找
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                    	//二级缓存中找
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                        	//三级缓存中找
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {	//找到了
                            	//这里相当于上面图文分析中BService在三级缓存中找到AService
                            	//直接用lambda表达式注册,然后把他移动到二级缓存中
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

但是显然AService肯定不会找到,然后就会重新走到createBean,创建一个BService,与A一样走到上述的getSingleton,这时会在三级缓存中找到A,然后注入

填充完成之后就会把BService放到一级缓存中,移除三级缓存中的B,然后结束

	exposedObject = this.initializeBean(beanName, exposedObject, mbd);

执行完整个BService的创建,上面的A的依赖填充才会结束,然后A也执行一遍exposedObject = this.initializeBean(beanName, exposedObject, mbd);这行代码,A也结束。

结合图文演示看代码更容易理解捏

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器中了360后缀勒索病毒,360后缀勒索病毒介绍解密数据恢复

360后缀勒索病毒&#xff0c;是BeijingCrypt勒索家族中的一种勒索软件病毒&#xff0c;这种恶意软件一旦攻击了企业的服务器就会利用自身独特的加密技术来全盘扫描系统文件&#xff0c;并对用户的全部文件进行加密&#xff0c;并要求用户支付赎金以解锁文件。近期&#xff0c;我…

C# 数据结构】Heap 堆

【C# 数据结构】Heap 堆 先看看C#中有那些常用的结构堆的介绍完全二叉树最大堆 Heap对类进行排序实现 IComparable<T> 接口 对CompareTo的一点解释 参考资料 先看看C#中有那些常用的结构 作为 数据结构系类文章 的开篇文章&#xff0c;我们先了解一下C# 有哪些常用的数据…

CNNdebug尝试

这算是啥问题&#xff1f;&#xff1f; 接着根据群里大佬提供的指示&#xff0c;将train和validate中的nums_work改成0即可 此处因为数据已经打乱了&#xff0c;所以在这里就不用打乱数据&#xff0c;把shuffle True修改成为False 后面查看指定目录下&#xff0c;竟然没有这个…

性能测试工具 Jmeter 引入 jar 包踩过的坑

目录 前言&#xff1a; Jmeter 中调用自己编写 jar 中的类出错 错误日志&#xff1a; 出现以上错误的原因&#xff1a; 解决方法&#xff1a; 前言&#xff1a; JMeter 是一种开源的性能测试工具&#xff0c;可以帮助我们快速地进行网站、应用程序等的性能测试和压力测试…

20230720在ubuntu22.04系统下载+解密+合并ts切片的步骤(STEP-BY-STEP版本)

20230720在ubuntu22.04系统下载解密合并ts切片的步骤&#xff08;STEP-BY-STEP版本&#xff09; 2023/7/20 23:06 https://app1ce7glfm1187.h5.xiaoeknow.com/v2/course/alive/l_64af6130e4b03e4b54da1681?type2&app_idapp1cE7gLFM1187&pro_idterm_645c69388953e_Nhew…

C# List 详解七

目录 42.Sort() 43.ToArray() 44.ToString() 45.TrimExcess() 46.TrueForAll(Predicate) C# List 详解一 1.Add(T)&#xff0c;2.AddRange(IEnumerable)&#xff0c;3.AsReadOnly()&#xff0c;4.BinarySearch(T)&#xff0c; C# List 详解二 5.Cl…

TEE GP(Global Platform)认证规范

TEE之GP(Global Platform)认证汇总 一、GP认证规范库 二、TEE GP认证规范文档 如果需要TEE对应的GP认证规范文档&#xff0c;请按照下方选择框选择TEE&#xff0c;然后Search&#xff0c;共查询到31个相关规范文档。 参考&#xff1a; GlobalPlatform Certification - Global…

[回馈]ASP.NET Core MVC开发实战之商城系统(一)

经过一段时间的准备&#xff0c;新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始&#xff0c;今天着重讲解布局设计&#xff0c;环境搭建&#xff0c;系统配置&#xff0c;及首页商品类型&#xff0c;banner条&#xff0c;友情链接等功能的开发。 首页布局设计 首页是…

工程安全监测无线振弦采集仪在建筑物中的应用

工程安全监测无线振弦采集仪在建筑物中的应用 工程安全监测无线振弦采集仪是一种用于建筑物结构安全监测的设备&#xff0c;它采用了无线传输技术&#xff0c;具有实时性强、数据精度高等优点&#xff0c;被广泛应用于建筑物结构的实时监测和预警。下面将从设备的特点、应用场…

(原创)自定义DialogFragment以及解决其内存泄漏问题

前言 日常开发中&#xff0c;dialog是常见的功能&#xff0c;我们时常需要弹出来一些弹框提示用户 今天就定义了一个方便的dialog基类BaseSimpleDialogFragment&#xff0c; 支持快速地显示一个dialog 主要功能有&#xff1a; initAnimation&#xff1a;设置入场和出场动画 ge…

【C进阶】指针进阶(1)_二次复习版

目录 1. 字符指针 1.1常量字符串的修改 加上const解决问题 打印常量字符串 1.2数组存放的字符串 1.3例题:数组创建与常量池的区别 2. 指针数组 2.1字符指针数组 2.2整型指针数组 2.3使用3个一维数组,模拟实现一个二维数组 2.4例题: 3.数组指针 3.1 数组指针的定义…

同步网盘使用中的五大突出优势

同步网盘是一种流行的云存储解决方案&#xff0c;它可以将您本地计算机上的文件与云端存储空间同步&#xff0c;以保证文件的备份和访问。那么&#xff0c;同步网盘使用中的突出优势是什么呢&#xff1f;下面就为您详细介绍。 一、数据备份 同步网盘最大的优势之一就是可以自动…

错误解决:Failed to create Spark client for Spark session

错误解决&#xff1a;Failed to create Spark client for Spark session "Failed to create Spark client for Spark session"的错误通常表示无法为Spark会话创建Spark客户端。这可能是由于以下一些常见问题导致的&#xff1a; Spark配置错误&#xff1a;请检查Spar…

智慧园区楼宇合集:数字孪生管控系统

智慧园区是指将物联网、大数据、人工智能等技术应用于传统建筑和基础设施&#xff0c;以实现对园区的全面监控、管理和服务的一种建筑形态。通过将园区内设备、设施和系统联网&#xff0c;实现数据的传输、共享和响应&#xff0c;提高园区的管理效率和运营效益&#xff0c;为居…

ubuntu开机自启动

ubuntu开机自启动 1、建一个test.sh脚本&#xff0c;并写入 #!/bin/sh gnome-terminal -x bash -c ‘cd /home/文件路径/;python3 main.py’ exit 0 2、:wq!保存 3、创建rc-local.service文件&#xff08;sudo vim /etc/systemd/system/rc-local.service&#xff09;&#xf…

一次线上OOM问题的个人复盘

我们一个java服务上线后&#xff0c;偶尔会发生内存OOM(Out Of Memory)问题&#xff0c;但由于OOM导致服务不响应请求&#xff0c;健康检查多次不通过&#xff0c;最后部署平台kill了java进程&#xff0c;这导致定位这次OOM问题也变得困难起来。 最终&#xff0c;在多次review代…

shell实现数据库分库分表备份

#!/bin/bash2 3 backup/backup/db #存放数据库的位置4 nodatabasesinformation_schema|mycat|performance_schema|sys|mysql #要过滤的数据库5 6 mysql -uroot -predhat -e "show databases" -N | egrep -v "${nodatabases}" > dbname #将数据库存放在…

跨境出海企业,如何防范恶意退货欺诈

很多出海企业遭遇到过恶意退货事件。 2021年&#xff0c;某跨境商家在海外电商平台运营超过13年。有一次&#xff0c;有个海外买家买了一台二手的数码摄像机。在买家收到货后&#xff0c;却声称商品备在使用了45分钟之后便自动关机&#xff0c;且不能继续充电。该商家很肯定产…

裁员 10%,暴跌 14%,这家 IT 独角兽正在被抛弃!

流量一跌再跌&#xff0c;Stack Overflow 简直被狠狠地上了一课&#xff01; 3 月份 Stack Overflow 的流量下降了近 14%。该公司的 CEO 压力空前&#xff0c;甚至昨天决定裁员 10%&#xff01; 平均每月下降6%&#xff0c;上月直接跌了近14% 开发人员越来越多地从 AI 聊天机器…

Audio2Face

1:下载链接。 Omniverse Enterprise 许可和定价 | NVIDIA 2:安装。 audio2face ue插件 教程&#xff1a; 1&#xff1a;【青松微课堂】Audio2Face数字人工作流&#xff1a;软件的下载安装与UI介绍 【青松微课堂】Audio2Face数字人工作流&#xff1a;软件的下载安装与UI介绍_…