[Spring] 三级缓存解决循环依赖详解
什么是循环依赖
注册一个bean对象的过程:
Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果原始对象种的某个方法被AOP了,那么要根据原始对象生成一个代理对象 – 把最终生成的代理对象放入单例池(singletonObjects,也叫一级缓存)中,下次getBea你就直接从单例池拿
循环依赖就是在依赖注入的时候相互注入,如
public class AService{@Autowiredprivate BService bService;
}
public class BService{@Autowiredprivate AService aService;
}
三级缓存过程
Spring使用了三级缓存的策略来解决循环依赖问题,过程大致如下
创建AService的bean:
因为暂时还没有BService,所以创建个BService
创建过程中,因为AService已经在三级缓存中出现过,所以会进行以下操作
因为BService的属性都已经赋值了,所以BService的初始化就结束了,可以直接放到一级缓存中,完整过程为:
此时BService已经实例化完成,那么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是是否允许循环依赖@Nullableprotected 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也结束。
结合图文演示看代码更容易理解捏
相关文章:

[Spring] 三级缓存解决循环依赖详解
什么是循环依赖 注册一个bean对象的过程: Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果…...

gerrit 从安装到出坑
一般公司在做代码审核的时候选择codereview gerrit来处理代码的入库的问题。 它是通过提交的时候产生Change-Id: If4e0107f3bd7c5df9e2dc72ee4beb187b07151b9 来决定是不是入库,一般如果不是通过这个管理,那么就是我们通常的操作 git add . git comm…...
Java工程师就业前景怎么样?能拿多少工资?
Java软件工程师是指运用Java这个开发工具去完成软件产品的软件程序设计、开发、测试、维护升级等工作的人员。Java程序员可以分为初级、中级、高级、资深等。不同级别的Java程序员,薪资也不一样。 Java除了一般的编程,还可以开发游戏、进行桌面设计、Ja…...

极速跳板机登陆服务器
目录 一:简单登陆跳板器二:一键申请相关的服务器权限三:简化登陆 一:简单登陆跳板器 登陆公司提供的网址, 下载自己的专属RSA密钥。在密钥文件处, 执行登陆指令: ssh -p 36000 -i id_rsa 用户跳…...

【算法与数据结构】226、LeetCode翻转二叉树
文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析:这道题的思路很简单,本质上就是遍历每一个节点,然后交换左右节点。我们可以用前…...
metaRTC6.0 new feature (一)
概要 metaRTC6.0社区版最新版是6.0.212,标准版最新版本是6.0.276,企业版基础版最新版本是6.0.362,在企业版和标准版新增了一些实用功能模块,文件数字证书模块将并入社区版。 New Feature rtsp协议支持 新增rtsp协议࿰…...

聊天机器人如何增加电子商务销售额
聊天机器人和自动化对企业和客户来说都是福音。自动对话和聊天机器人(以下统称为“自动化”)通过自动回答问题或分配会话信息来帮助用户浏览品牌网站或电商商店。即时答案对客户来说非常有用,使用自动化也可以让原本与客户聊天的客服员工专注…...

stm32 IIC通信
文章目录 IIC 通信一、硬件电路二、IIC时序基本单元三、IIC时序1.指定地址写2.当前地址读3.指定地址读 IIC 通信 IIC总线是一种通用数据总线,有两根通信线(SCL(串行时钟总线),SDA(串行数据总线))。 特点:同…...

Elasticsearch监控工具Cerebro安装
Elasticsearch监控工具Cerebro安装 1、在windwos下的安装 1.1 下载安装包 https://github.com/lmenezes/cerebro/releases/download/v0.9.4/cerebro-0.9.4.zip 1.2 解压 1.3 修改配置文件 如果需要修改相关信息,编辑C:\zsxsoftware\cerebro-0.9.4\conf\applica…...

RTOS 低功耗设计原理及实现
RTOS 低功耗设计原理及实现 文章目录 RTOS 低功耗设计原理及实现👨🏫前言👨🔬Tickless Idle Mode 的原理及实现👨🚀Tickless Idle Mode 的软件设计原理👨💻Tickless Idle Mo…...

PaddleOCR C++编译出错解决方案
文章目录 前言一、环境准备1、主要环境2、源码下载3、C推理库下载 二、报错信息1.静态库调用错误2.ld returned 1 exit status 总结 前言 最近,想尝试下PaddleOCR的C推理,但是过程不如人所愿,除了很多问题,这里捡重点的说下吧&…...
89、简述RabbitMQ的架构设计
简述RabbitMQ的架构设计 BrokerQueueExchangeRoutingKeyBinding信道架构设计图Broker RabbitMQ的服务节点 Queue 队列,是RabbitMQ的内部对象,用于存储消息。RabbitMQ中消息只能存储在队列中。生产者投递消息到队列,消费者从队列中获取消息并消费。多个消费者可以订阅同一…...
63 | 图像处理
文章目录 Python图像处理什么是图像处理?Python图像处理库安装Pillow库加载和显示图像调整图像大小裁剪图像调整图像亮度、对比度和色彩平衡应用滤镜练习题Python图像处理 什么是图像处理? 图像处理是指使用计算机算法来改变图像的外观或特征。它可以用于许多不同的应用程序…...

Stable Diffusion - 扩展 Roop 换脸 (Face Swapping) 插件的配置与使用
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/131856141 官网:GitHub - roop,参考论文:RobustSwap: A Simple yet Robust Face Swapping Model against Attr…...
opencv实现替换证件照颜色
程序可以实现蓝色底片变为红色底片(但有点小bug) 修改自:opencv:HSV颜色模型_opencv hsv_君浪的博客-CSDN博客 相关文章:OpenCV Mat数据类型指针ptr的使用_cv::mat ptr_AoboSir的博客-CSDN博客 【OpenCV】HSV颜色识…...

Elasticsearch【全文检索、倒排索引、应用场景、对比Solr、数据结构】(一)-全面详解(学习总结---从入门到深化)
目录 Elasticsearch介绍_全文检索 Elasticsearch介绍_倒排索引 Elasticsearch介绍_Elasticsearch的出现 Elasticsearch介绍_Elasticsearch应用场景 Elasticsearch介绍_Elasticsearch对比Solr Elasticsearch介绍_Elasticsearch数据结构 Elasticsearch介绍_全文检索 Elasti…...

了解 3DS MAX 3D摄像机跟踪设置:第 2 部分
推荐: NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25,将持续时间设置为 12 秒。单…...
MySQL 判断 JSON 数组是否相等
文章目录 1.问题2.使用 JSON_CONTAINS 与 JSON_LENGTH参考文献 1.问题 JSON(JavaScript Object Notation)是流行的互联网应用服务之间的数据交换格式。 MySQL 从 5.7 版本开始支持 RFC 7159 定义的 JSON 规范,主要有 JSON 对象 和 JSON 数组…...

uni-app个人中心
一. 介绍uni-app: uni-app 是基于Vue.js框架开发的一个跨平台移动应用开发框架,可以同时支持多个平台(如iOS、Android、Web等)的应用开发。采用了统一的语法和组件规范,可以大大简化跨平台开发的工作,提高…...

只需3步,使用Stable Diffusion无限生产AI数字人视频
效果演示 先看效果,感兴趣的可以继续读下去。 没有找到可以上传视频的地方,大家打开这个网盘链接观看:https://www.aliyundrive.com/s/CRBm5NL3xAE 基本方法 搞一张照片,搞一段语音,合成照片和语音,同…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...