Spring解决循环依赖问题

一、什么是循环依赖?


例如,就是A对象依赖了B对象,B对象依赖了A对象。(下面的代码属于属性的循环依赖,也就是初始化阶段的循环依赖,区别与底下构造器的循环依赖)

  // A依赖了Bclass A{public B b;} // B依赖了Aclass B{public A a;}
A a = new A();B b = new B();a.b = b;b.a = a;

问题来了:
A Bean创建 ——> 依赖了 B 属性 ——>  触发 B Bean创建 ——>  B 依赖了 A 属性 ——>  需要 A Bean(但A Bean还在创建过程中)

二、怎么解决?使用三级缓存


一级缓存为:singletonObjects; 终态 Bean
二级缓存为:earlySingletonObjects; 临时Bean
三级缓存为:singletonFactories;


/** Cache of singleton objects: bean name –> bean instance */
private final Map singletonObjects = new ConcurrentHashMap(256);/** Cache of singleton factories: bean name –> ObjectFactory */
private final Map singletonFactories = new HashMap>(16);/** Cache of early singleton objects: bean name –> bean instance */
private final Map earlySingletonObjects = new HashMap(16);


singletonObjects」中缓存的是已经经历了完整生命周期的bean对象。(用户查询SpringBeanUtil.getBean,也是查一级缓存,因为查二级缓存,可能npe,因为二级缓存的bean是没加载完的,属性可能还没赋值)

earlySingletonObjects」比 singletonObjects 多了一个 early ,表示缓存的是早期的 bean对象。早期指的是 Bean 的生命周期还没走完就把这个 Bean 放入了 earlySingletonObjects。

singletonFactories」中缓存的是 ObjectFactory,表示对象工厂,用来创建某个对象的。
 

在这里插入图片描述

1、A初始化的时候,需要B,但是B没有,所以创建B,

2、B 创建的时候,需要A,A现在还没完事呢,那么会把A 放到 earlySingletonObjects ,B成功取到 A, B创建成功,B放到 SingletonObjects

3、A 从 SingletonObjects 取到 B,A完成初始化

4、A初始化后,会从 earlySingletonObjects 挪到 SingletonObjects 

————————

上面这个步骤没利用只用到了2级缓存,你会发现 B内部的A属性其实存的是 A的原始对象,不是A的终极对象,也就是有2个A对象,一个位于SingletonObjects ,一个位于 earlySingletonObjects 

————————

三级缓存如何解决这个问题?

1、每个对象在创建的时最开始,都会先把自己丢到 singletonFactories 三级缓存里面去

2、初始化的时候,就是给属性 b 赋值的时候,从三级缓存里面getObject就会给你把 b 对象丢给你,就自始至终都是这个对象

3.1 为什么无法解决构造器的循环依赖问题?

 public class A {B b;public A(B b) {this.b = b;}}public class B {A a;public B(A a) {this.a = a;}}

首先,对象最开始分为两个阶段:实例化阶段(创建阶段) + 初始化阶段 

初始化阶段,主要是给对象内的属性赋值。

实例化阶段,会调用对象的构造函数。

只有实例化后的对象,才会放到三级缓存中去,构造函数是在实例化时调用的,那就都拿不到,没法解决这个问题。

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

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

相关文章

深入理解 go协程 调度机制

Thread VS Groutine 这里主要介绍一下Go的并发协程相比于传统的线程 的不同点: 创建时默认的stack大小 JDK5 以后Java thread stack默认大小为1MC 的thread stack 默认大小为8MGrountine 的 Stack初始化大小为2K 所以Grountine 大批量创建的时候速度会更快 和 …

Photoshop制作漂亮光泽感3D按钮

原文链接(https://img-blog.csdnimg.cn/45472c07f29944458570b59fe1f9a0e0.png)

【数据结构与算法】十大经典排序算法-归并排序

🌟个人博客:www.hellocode.top 🏰Java知识导航:Java-Navigate 🔥CSDN:HelloCode. 🌞知乎:HelloCode 🌴掘金:HelloCode ⚡如有问题,欢迎指正&#…

在vue中使用swiper轮播图(搭配watch和$nextTick())

在组件中使用轮播图展示图片信息: 1.下载swiper,5版本为稳定版本 cnpm install swiper5 2.在组件中引入swiper包和对应样式,若多组件使用swiper,可以把swiper引入到main.js入口文件中: import swiper/css/swiper.css //引入swipe…

Redis基础概念和数据类型详解

目录 1.什么是Redis? 2.为什么要使用Redis? 3.Redis为什么这么快? 4.Redis的使用场景有哪些? 5.Redis的基本数据类型 5.1 5种基础数据类型 5.1.1 String字符串 5.1.2 List列表 5.1.3 Set集合 5.1.4 Hash散列 5.1.5 Zset有序集…

如何修复损坏的DOC和DOCX格式Word文件?

我们日常办公中,经常用到Word文档。但是有时会遇到word文件损坏、无法打开的情况。这时该怎么办?接着往下看,小编在这里就给大家带来最简单的Word文件修复方法! 很多时候DOC和DOCX Word文件会无缘无故的损坏无法打开,一…

UNIAPP中开发企业微信小程序

概述 需求为使用uni-app开发企业微信小程序。希望可以借助现成的uni-app框架,快速开发。遇到的问题是uni-app引入jweixin-1.2.0.js提示异常: Reason: TypeError: Cannot read properties of undefined (reading ‘title’)。本文中描述了如何解决该问题&#xff0c…

Mybatis的学习笔记(IDEA快捷键,参数占位符,转义符)

一、IDEA快捷键: IDEA多行注释:ctrlShift/ 单行注释:ctrl/ 导入包,自动修正代码:altenter 自动生成代码:altinsert 二、Mybatis重要知识点: 2.1 参数占位符 一共分为2种:#{}和…

【gitkraken】gitkraken自动更新问题

GitKraken 会自动升级&#xff01;一旦自动升级&#xff0c;你的 GitKraken 自然就不再是最后一个免费版 6.5.1 了。 在安装 GitKraken 之后&#xff0c;在你的安装目录&#xff08;C:\Users\<用户名>\AppData\Local\gitkraken&#xff09;下会有一个名为 Update.exe 的…

Eclipse集成MapStruct

Eclipse集成MapStruct 在Eclipse中添加MapStruct依赖配置Eclipse支持MapStruct①安装 m2e-aptEclipse Marketplace的方式安装Install new software的方式安装&#xff08;JDK8用到&#xff09; ②添加到pom.xml 今天拿到同事其他项目的源码&#xff0c;导入并运行的时候抛出了异…

LVS负载均衡集群-NAT模式部署

集群 集群&#xff1a;将多台主机作为一个整体&#xff0c;然后对外提供相同的服务 集群使用场景&#xff1a;高并发的场景 集群的分类 1.负载均衡器集群 减少响应延迟&#xff0c;提高并发处理的能力 2&#xff0c;高可用集群 增强系统的稳定性可靠性&…

SCF金融公链新加坡启动会 链结创新驱动未来

新加坡迎来一场引人瞩目的金融科技盛会&#xff0c;SCF金融公链启动会于2023年8月13日盛大举行。这一受瞩目的活动将为金融科技领域注入新的活力&#xff0c;并为广大投资者、合作伙伴以及关注区块链发展的人士提供一个难得的交流平台。 在SCF金融公链启动会上&#xff0c; Wil…