Spring如何解决循环依赖

news2024/11/27 12:43:56

今天面试了同程旅行,面试官问到了这个问题,所以今天来总结学习一下 Spring是如何解决循环依赖问题?

前言

Spring的依赖注入分为 setter注入构造器注入
这里说的解决循环依赖主要指的是:单例模式下的setter循环依赖

如果是:构造器的循环依赖非单例循环依赖。 Spring都是解决不了的

Spring的生命周期

讲循环依赖的问题,需要先说说Spring生命周期这个问题,先看看在Spring中,一个Bean从创建到销毁经历过哪些过程?

Spring中的bean的生命周期主要包含四个阶段:实例化Bean --> Bean属性填充 --> 初始化Bean -->销毁Bean

什么是循环依赖

我们定义这样两个类A、B,A中有一个属性引用的B,B中有一个属性是引用的A

参考上面Bean的生命周期,就能得出:在实例化A的时候,去赋值属性B,就去找B,B这个时候又需要实例化赋值属性A的时候,又去找A。接着A又找B,就形成了循环依赖。

@Component
public class A{
  @Autowired
  B b;
}

@Component
public class B{
  @Autowired
  A a;
}

Spring的三级缓存

// 1级缓存:存放完全初始化好的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 2级缓存:存放实例化(尚未填充属性)+代理(如果有代理)后的单例bean
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

//3级缓存,存放bean工厂对象,用于解决循环依赖
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

假设只有一级缓存

如果A在实例化过后,不进行属性值的填充,就把它丢到一级缓存里面行吗?其实这样缓存里面的A也不是一个真正的A,它缺胳膊少腿,用它的时候回报一个空指针异常,而且我们的一级缓存规定是完全初始化好的bean才放在一级缓存立面,给我们的程序后续进行使用

假设只有二级缓存

我们把一级缓存叫 Map1,二级缓存叫Map2

首先还是从实例化A开始,我们对A实例化过后,还没有进行属性填充的时候,就把A对象的引用放在Map2备用,然后进行属性填充,A去填充B的时候,发现B没有实例化;于是等B同样实例化过后,B也把自己的引用放在Map2中,B开始进行属性填充,发现Map1中没有A,但在Map2中找到了A,是自己装填完整。这个时候B把完整的自己放在了Map1,随手把Map2中的半成品删除。
再回到A的阶段,A中发现Map1中有了B,那么A也可以装填完整,于是最终A、B都完成了自己的创建。

文字有点儿扭成一坨不容易看懂,我画个流程图,大家凑合看

在这里插入图片描述
按照以上所述,二级缓存已经完美解决了循环依赖的问题,为什么Spring还需要引入三级缓存来做呢?

主要原因是因为:Spring的Aop产生的代理对象

Srping的代理对象产生阶段是在填充属性后才进行,原理是通过后置处理器BeanPostProcssor来实现

如果 Spring 选择二级缓存来解决循环依赖的话,那么就意味着所有 Bean 都需要在实例化完成之后就立马为其创建代理

所以Spring选择使用三级缓存,因为循环依赖的出现,导致了 Spring 不得不提前去创建代理,因为如果不提前创建代理对象,那么注入的就是原始对象,这样就会产生错误。

Spring的三级缓存

首先我们还是进行实例化A对象,我们将A的ObjectFactory对象放入Map3中,同样进行属性填充,这个时候发现需要属性B,这个时候B还没有创建。
接着去创建B,实例化B的过程中,一样的我们先将B的ObjectFactory放到Map3中,继续执行B的属性填充,去寻找A对象。此时Map1和Map2中都没有找到A对象,但在Map3中发现了有A的 ObjectFactory对象,那么我们就可以通过这个 ObjectFactory对象获取到A的早期对象,并且把A早期对象放到Map2中国,同时删除Map3中的A,我们把Map2中的早期对象A给了B,让B对象进行属性装填,接着B完整了,就把B放入到一级缓存当中,再把Map3中B的 ObjectFactory删除。
B创建完成,A继续执行b属性的填充就可以拿到Map1中拿到B对象,这样A也完整了。
最后把A对象放入到Map1单重,删除Map2中的A,于是我们的循环依赖的解决了

画一张流程图试着理解一下:

在这里插入图片描述

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

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

相关文章

ThreadLocal使用与原理

目录一、ThreadLocal1.ThreadLocal简介1.1 是什么2.能干嘛1.3 api介绍1.4 实战1.5 通过上面代码总结2.从阿里ThreadLocal规范开始3.ThreadLocal源码分析3.1 Thread&#xff0c;ThreadLocal&#xff0c;ThreadLocalMap 关系3.2 总结4.ThreadLocal内存泄露问题4.1 什么是内存泄漏…

PCIE 学习笔记(入门简介)

PCIE 学习笔记书到用时方恨少啊&#xff0c;一年前学PCIE的笔记&#xff0c;再拿出来瞅瞅。发到博客上&#xff0c;方便看。PCIE基础PCIE和PCI的不同PCIE采用差分信号传输&#xff0c;并且是dual-simplex传输——每条lane上有TX通道和RX通道&#xff0c;所以每条lane上的信号是…

DBeaver连接达梦数据库

1、下载Dbeaver安装包 1、官网下载&#xff1a;Download | DBeaver Community 2、下载完成后双击运行.exe文件&#xff0c;进行安装 2、配置达梦数据库驱动 1、达梦数据库驱动下载&#xff1a;Mybatis 框架 | 达梦技术文档 2、为DBeaver添加驱动 3、自定义DM驱动管理器的相关配…

购买低代码平台,要考量哪些指标?

近些年来&#xff0c;低代码平台的热度在逐渐上升&#xff0c;可以看出企业数字化转型得速度也在逐渐加快。企业的数字开发需求越来越强&#xff0c;市场之间的竞争也愈演愈烈。特别是对于中小型企业&#xff0c;既要考虑到产品功能需求&#xff0c;又要考虑成本压力&#xff0…

安卓小游戏:飞机大战

安卓小游戏&#xff1a;飞机大战 前言 前面写了十二篇自定义view的博客&#xff0c;说实话写的还是有点无聊了&#xff0c;最近调整了一下&#xff0c;觉得还是要对开发有热情&#xff0c;就写了点小游戏&#xff0c;现在抽时间把博客也写一写&#xff0c;希望读者喜欢。 需…

渲染速度特别慢,使用云渲染会快多少?

设计师在使用软件制作效果图和动画师在制作动画时&#xff0c;其中有一个比较关键的环节就是渲染成像&#xff0c;渲染的效率主要跟使用的电脑显卡或CPU性能有关&#xff0c;如果性能太低&#xff0c;渲染的速度会很慢&#xff0c;拉长了项目整体的交付周期&#xff0c;云渲染速…

反转链表的两种方法

大家好&#xff0c;今天和大家分享的是反转链表的两种方法&#xff0c;第一种是用泛型编程里面的STL&#xff0c;第二种是利用多个指针进行操作&#xff0c;小孩子才做选择&#xff0c;建议两个都学。我们往下看&#xff1a;一.使用vector容器ps&#xff1a;该方法对内存的需求…

LeetCode刷题--- 430. 扁平化多级双向链表(双指针)

文章目录一、编程题&#xff1a;430. 扁平化多级双向链表&#xff08;双指针&#xff09;1.题目描述2.示例1&#xff1a;3.示例2&#xff1a;4.示例3&#xff1a;5.提示&#xff1a;二、解题思路1.思路2.复杂度分析&#xff1a;3.算法图解三、代码实现总结一、编程题&#xff1…

网页防篡改实验(6)

实验简介 实验所属系列&#xff1a;网络攻防工具 实验对象&#xff1a; 本科/专科信息安全专业 相关课程及专业&#xff1a;信息网络安全概论、计算机网络 实验时数&#xff08;学分&#xff09;&#xff1a;2学时 实验类别&#xff1a;实践实验类 实验目的 1、了解网页防篡改…

7.数据库设计

学习过程参考&#xff08;后续章节同&#xff09; 【公开课】数据库系统概论&#xff08;王珊老师&#xff09;&#xff08;完结&#xff09; 《数据库系统概论》思维导图 第7章 数据库设计 | 数据库知识点整理 梳理 名词解释 数据库设计(database design)&#xff1a;数据库…

从2023年31省级政府工作报告看数据安全赛道 | 附下载

数字经济是支撑我国经济增长的新动能。据中国信息通信研究院数据&#xff0c;2021年我国数字经济规模超45万亿元、在GDP已占比40%&#xff0c;到2025年我国数字经济规模预计超60万亿元。春节前夕&#xff0c;地方两会陆续召开&#xff0c;从各地发布的2022年经济社会发展成绩来…

NodeJS与npm版本不一致时降级npm的方法

首先查看 Node.js 与 npm 版本对应关系&#xff1a;Node.js与npm版本查看。 安装 cnpm&#xff1a; npm install -g cnpm 查看一下 npm 和 cnpm 的镜像&#xff1a; npm config get registry cnpm config get registry 2 如果不是 https://registry.npm.taobao.org/ 的话就修…

【C++】CC++内存管理

就是你被爱情困住了&#xff1f;Wake up bro&#xff01; 文章目录一、C/C内存分布二、C语言中动态内存管理方式三、C中内存管理方式1.new和delete操作内置类型2.new和delete操作自定义类型&#xff08;仅限vs的底层实现机制&#xff0c;new和delete一定要匹配使用&#xff0c;…

【Linux】TCP网络编程流程

TCP网络编程流程 上一节博文我们提到了网络编程的基本流程 现在我们来了解TCP网络编程的流程 在这之前我们先要了解TCP 首先TCP是一种传输控制协议 在因特网协议族&#xff08;Internet protocol suite&#xff09;中&#xff0c;TCP层是位于IP层之上&#xff0c;应用层之…

MIT 6.S965 韩松课程 02

Lecture 02: Basics of Neural Networks TitleBasics of Neural NetworksLecturerSong HanDate09/13/2022Note AuthorGuangxuan Xiao (xgx)DescriptionReview the basics of deep learning and introduce efficiency metrics for neural networks. 回顾深度学习的基础知识&…

SparkSQL 核心编程

文章目录SparkSQL 核心编程1、新的起点2、SQL 语法1) 读取 json 文件创建 DataFrame2) 对 DataFrame 创建一个临时表3) 通过SQL语句实现查询全表3、DSL 语法1) 创建一个DataFrame2) 查看DataFrame的Schema信息3) 只查看"username"列数据4) 查看"username"列…

Elasticsearch(九)搜索---搜索辅助功能(下)--搜索性能分析

一、前言 上篇文章我们学习了ES的搜索辅助功能的一部分–分别是指定搜索返回的字段&#xff0c;搜索结果计数&#xff0c;分页&#xff0c;那么本次我们来学习一下ES的性能分析相关功能。 二、ES性能分析 在使用ES的过程中&#xff0c;有的搜索请求的响应比较慢&#xff0c;…

ChatGPT的火爆出圈,你对它有几分了解?

文章目录1.ChatGPT是什么&#xff1f;2.ChatGPT能做什么&#xff1f;2-1.什么是自然语言模型&#xff1f;3.ChatGPT带来的评价4.了解完ChatGPT之后&#xff0c;你会有什么反思&#xff1f;4-1.为什么微软不自己研发ChatGPT&#xff1f;4-2.Elon Musk为什么退出OpenAI公司&#…

分享116个JS焦点图代码,总有一款适合您

分享116个JS焦点图代码&#xff0c;总有一款适合您 116个JS焦点图代码下载链接&#xff1a;https://pan.baidu.com/s/1BKblAjuE98y5HlLAXZIndQ?pwdphgw 提取码&#xff1a;phgw Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj import os impo…

全国青少年编程等级考试scratch二级真题2022年9月(含题库答题软件账号)

青少年编程等级考试scratch真题答题考试系统请点击电子学会-全国青少年编程等级考试真题Scratch一级&#xff08;2019年3月&#xff09;在线答题_程序猿下山的博客-CSDN博客_小航答题助手1.数列&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;6&#xff0c;…