Spring 为什么使用三级缓存解决循环依赖

文章目录

    • 前言
      • 1. 什么是循环依赖
        • 1.1 互相依赖
        • 1.2 递归依赖
      • 2. Sping中循环依赖有什么问题?
      • 3. 什么是三级缓存
      • 4. Spring 可以解决哪些情况的循环依赖?
    • 二级缓存作用——普通循环依赖
      • 实操环节
        • 1. 实例化类A对象
        • 2. 实例化类B对象
        • 3. B对象完成创建
        • 4.继续创建A对象
    • 三级缓存作用——aop循环依赖
      • 1. AOP代理问题
      • 2. 何时生成代理对象
      • 实操环节
        • 1.实例化类A对象
        • 2. 实例化类B对象
        • 3.继续创建A对象
    • 结尾




前言

1. 什么是循环依赖

  类A需要类B,我们就叫做类A依赖类B。简单说就是⾃⼰依赖⾃⼰,或者和别的类相互依赖


1.1 互相依赖

1.2 递归依赖

在这里插入图片描述


2. Sping中循环依赖有什么问题?

  在Spring中,循环依赖指的是两个或多个Bean之间相互依赖形成的循环引用关系。具体来说,当Bean A依赖于Bean B,而Bean B又依赖于Bean A时,就形成了循环依赖。

  只有单例的 Bean 才存在循环依赖的情况,原型(Prototype)情况下,Spring 会直接抛出异常。

  循环依赖可能导致以下问题:

  • 无法完成Bean的初始化:当存在循环依赖时,Spring容器无法确定先初始化哪个Bean,因为它们相互依赖,而且都需要对方完成初始化才能继续。这可能导致Bean的初始化过程无法完成,从而引发异常。

  • 无限递归调用:当存在循环依赖时,Spring容器可能会陷入无限递归的调用中,导致系统堆栈溢出。这是因为每次获取Bean时,Spring容器需要检测循环依赖并创建实例,但由于循环依赖的存在,无法正常创建实例,从而导致无限递归调用。

在这里插入图片描述

  为了解决循环依赖问题,Spring使用了三级缓存和"提前暴露"的策略


3. 什么是三级缓存

  对于创建单例Bean,Spring创建了三个容器来存储不同时期的对象:

  1. ⼀级缓存 : Map<String,Object> singletonObjects,单例池,⽤于保存实例化、属性赋值
    (注⼊)、初始化完成的 bean 实例
  2. ⼆级缓存 : Map<String,Object> earlySingletonObjects,早期曝光对象,⽤于保存实例化完
    成的 bean 实例
  3. 三级缓存 : Map<String,ObjectFactory<?>> singletonFactories,早期曝光对象⼯⼚,⽤于
    保存 bean 创建⼯⼚,以便于后⾯扩展有机会创建代理对象
    在这里插入图片描述

4. Spring 可以解决哪些情况的循环依赖?

  Spring 不⽀持基于构造器注⼊的循环依赖,假如 AB 循环依赖,其中一方使用构造器注入,也是不支持的。

在这里插入图片描述

  为什么呢?下面二级缓存会说明白。




二级缓存作用——普通循环依赖

  只用一级缓存和二级缓存就能解决普通bean的循环依赖。
  先回顾Bean对象创建的步骤:
在这里插入图片描述

  二级缓存:又称 半成品池 存放的是实例化,但未属性赋值和初始化的Bean对象。
  一级缓存:又称 单例池 存放的是完成属性赋值和初始化的成品Bean,可以直接使用了。

  那么二级缓存是如何解决普通Bean的循环依赖的?


实操环节

  类A依赖类B,类B依赖类A。

在这里插入图片描述

1. 实例化类A对象

  对象a被实例化出来,会被放到半成品池中,当进行下一步属性赋值时,发现依赖了类B,所以开始创建对象b。
在这里插入图片描述

  如果对象b是在a的构造函数中注入的,那就完了,a无法实例化,得先去实例化b,若是b也是构造函数中注入的a,那就无解了。

public class A {private B b;@Injectpublic A(B b) {this.b = b;}
}

2. 实例化类B对象

  对象b被实例化出来,也被放到半成品池中。下一步是属性赋值,发现依赖了类A,会依次从⼀级到三级缓存查询类A对象,最终会在半成品池中找到对象a,成功将它赋值到自己的属性中。
在这里插入图片描述

3. B对象完成创建

  对象b在经过填充属性、初始化后会从半成品池里挪到单例池中,可以直接使用了。
在这里插入图片描述

4.继续创建A对象

  这时候回过头来继续对象a的属性注入,把对象b赋值给自己的属性后再经过初始化,对象a也从半成品池挪到单例池,对象a创建完成,对象b也跟着创建完成。
在这里插入图片描述



三级缓存作用——aop循环依赖

  二级缓存仍然存在问题,它无法解决AOP代理问题。

1. AOP代理问题

  AOP(面向切面)简单的说,在不改源码的情况下在原始方法前后加一些代码。
  它的底层是靠动态代理实现的,即生成一个代理类,重新原始方法,真正使用的时候其实用的是代理类对象,而非原始类对象。
  既然用的是代理类对象,单例池中应该存放的就该是代理类对象。
  二级缓存无法解决生成代理对象的问题,因为创建对象的过程很复杂,每个代理类都需要一个工厂来专门生成代理类对象。
在这里插入图片描述

  三级缓存又叫工厂池,就是用来存放生成代理类对象工厂的
在这里插入图片描述

2. 何时生成代理对象

  AOP是靠AOP处理器实现的,处理器有两个生成代理对象的方式。

  • 前置处理:在Bean对象初始化后
  • 后置处理:再Bean对象实例化前
    在这里插入图片描述
      Spring为了解决使用AOP的对象循环依赖的问题,使用了这两种处理方式。

实操环节

  类A依赖类B,类B依赖类A,类A使用了AOP。
在这里插入图片描述

1.实例化类A对象

  首先把创建类A代理对象的工厂对象放到工厂池中。
在这里插入图片描述
  类A实例化对象时发现依赖了类B,使用前置处理器生成A的代理对象,放在半成品池子中。
在这里插入图片描述

2. 实例化类B对象

  对象b找到对象a,成功属性赋值,再经过初始化成功创建,挪到单例池中待用。
  如果类B也使用了AOP,那么对象b在初始化后,会通过后置处理器生成动态代理对象,放到单例池中。
在这里插入图片描述

3.继续创建A对象

  对象b创建完,接着回头创建对象a,这个过程就很顺利了。
  当对象a完成初始化以后,因为已经是代理对象,就不会在走后置处理。
  对象a、b都创建完,会清空在二级、三级池中的相关数据,最终只在单例池中保留一份对象。
在这里插入图片描述




结尾

  尽管Spring提供了解决循环依赖的机制,但循环依赖本身是一个设计上的问题,可能导致代码的可读性和可维护性下降。因此,在编写代码时,应尽量避免出现循环依赖的情况。

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

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

相关文章

数字图像处理—— Lab、YCbCr、HSV、RGB之间互转

Lab “Lab” 图像格式通常指的是 CIELAB 色彩空间&#xff0c;也称为 Lab 色彩空间。它是一种用于描述人类视觉感知的颜色的设备无关色彩空间&#xff0c;与常见的 RGB 和 CMYK 色彩空间不同。CIELAB 由国际照明委员会&#xff08;CIE&#xff09;于1976年定义&#xff0c;用于…

数据驱动工作效率提升的5个层次—以PreMaint设备数字化平台为例

在现代工业领域&#xff0c;数据分析已成为提升工作效率和优化生产的不可或缺的工具。从描述性分析到规范性分析&#xff0c;数据分析逐步揭示了设备运行和维护的深层信息&#xff0c;帮助企业更明智地做出决策。本文将以PreMaint设备数字化平台为例&#xff0c;探讨工业数据驱…

Wireshark数据抓包分析之ARP协议

一、实验目的&#xff1a; 通过wireshark的数据抓包了解这个ARP协议的具体内容 二、预备知识: 1.Address Resolution Protocol协议&#xff0c;就是通过目标IP的值&#xff0c;获取到目标的mac地址的一个协议 2.ARP协议的详细工作过程&#xff0c;下面描述得非常清晰&#xff…

230814期优橙5G网络优化就业班开班啦!这样的学习环境泰酷辣!~

230814期为期8天的基础班顺利结束&#xff01; 接下来就是为期3个月的就业班 小优橙一点都不敢耽搁时间 紧跟优橙老师教学节奏 今日通知 230814期优橙就业班今天已经正式开班&#xff01; 本次就业班有哪些新收获&#xff01; 快来跟着学员视角看看8天在优橙真实感受吧~…

【方案】安防监控EasyCVR智慧工地视频监管风险预警平台的应用

智慧工地方案是一种结合现代化技术与工地管理实践的创新型解决方案。它通过实时监控、数据分析、人工智能等技术手段&#xff0c;使工地管理更加高效、智能化。在建设智慧工地的过程中&#xff0c;除了上述提到的利用物联网技术实现设备互联、数据采集及分析以外&#xff0c;还…

【Linux】权限问题

Linux权限 一、Linux 权限的概念二、Linux 权限管理1. 文件访问者的分类2. 文件类型和访问权限&#xff08;事物属性&#xff09;3. 文件访问权限的相关设置方法 三、默认权限1. 对文件和目录进行操作需要的权限2. 文件和目录的默认权限3. 粘滞位 一、Linux 权限的概念 Linux …

Linux网络编程1(网络基础定义)

网络早已成为我们日常生活的一部分&#xff0c;经常使用互联网的人很难长时间内离开互联网。你是否好奇你的电脑仅仅插上一根网线&#xff0c;你发给朋友的聊天信息就能准确无误的到达朋友的手机或者电脑上&#xff0c;你是否好奇为何你仅仅在浏览器输入一个网址&#xff0c;点…

亿赛通电子文档安全管理系统 RCE漏洞

亿赛通电子文档安全管理系统 RCE漏洞 一、 产品简介二、 漏洞概述三、 复现环境四、 漏洞复现小龙POC检测: 五、 修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失…

【力扣】77. 组合 <回溯、回溯剪枝>

目录 【力扣】77. 组合题解回溯回溯法三步剪枝优化 【力扣】77. 组合 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按任何顺序返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2]…

嵌入式学习之linux

今天&#xff0c;主要对linux文件操作原理进行了学习&#xff0c;主要学习的内容就是对linux文件操作原理进行理解。写的代码如下&#xff1a;

【AI】即使AI 时代,程序员也无需焦虑

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

LLMs参考资料第一周以及BloombergGPT特定领域的训练 Domain-specific training: BloombergGPT

1. 第1周资源 以下是本周视频中讨论的研究论文的链接。您不需要理解这些论文中讨论的所有技术细节 - 您已经看到了您需要回答讲座视频中的测验的最重要的要点。 然而&#xff0c;如果您想更仔细地查看原始研究&#xff0c;您可以通过以下链接阅读这些论文和文章。 1.1 Trans…

C++:编译与链接

首先要思考问什么要编译与链接&#xff0c;首先这是一个如何把源程序即写好的代码编程可执行文件的过程&#xff0c;简单的加工模型如下图&#xff1a; 这是一个简单的加工模型&#xff0c;比较直观&#xff0c;但是有一个问题&#xff0c;就是如果对源程序进行修改&#xff0c…

OAuth2.0 客户端实战

上一次课程&#xff0c;我们了解了 OAuth 认证是怎么回事&#xff0c;以及了解了四种认证方式&#xff0c;今天我们将以 Github 为例&#xff0c;了解一下如何用 Flask 第三方应用 在之前的介绍 JWT 的时候&#xff0c;了解过 Authlib 库&#xff0c;Authlib 是集 JWT、OAuth1…

Go 语言的实战案例 | 青训营

Powered by:NEFU AB-IN 文章目录 Go 语言的实战案例 | 青训营 Go补充简介猜数游戏在线词典项目 Go 语言的实战案例 | 青训营 GO语言工程实践课后作业&#xff1a;实现思路、代码以及路径记录 Go补充简介 在计算机编程领域&#xff0c;Go 语言&#xff08;也称为 Golang&…

[C++] STL_vector使用与常用接口的模拟实现

文章目录 1、vector的介绍2、vector的使用2.1 vector的定义2.2 vector迭代器的使用2.3 vector的空间增长问题 3、vector的增删查改3.1 push_back&#xff08;重点&#xff09;3.2 pop_back&#xff08;重点&#xff09;3.3 operator[]&#xff08;重点&#xff09;3.4 insert3.…

【SQL中DDL DML DQL DCL所包含的命令】

SQL中DDL DML DQL DCL所包含的命令 关于DDL、DML、DQL、DCL的定义和适用范围如下&#xff1a; 数据定义语言&#xff08;Data Definition Language&#xff0c;DDL&#xff09;&#xff1a; DDL用于创建、修改和删除数据库中的表、视图、索引等对象。它的主要命令包括CREATE、A…

ATA-7000系列高压放大器——应用场景介绍

ATA-7000系列是一款理想的可放大交、直流信号的高压放大器。单端输出20kVp-p&#xff08;10kVp&#xff09;高压&#xff0c;可以驱动高压型负载。电压增益数控可调&#xff0c;一键保存常用设置&#xff0c;为您提供了方便简洁的操作选择。 图&#xff1a;ATA-7000系列高压放大…

shell 06(shell内置命令)

一、内置命令介绍 shell 内置命令&#xff0c;就是由 Bash shell 自身提供的命令&#xff0c;而不是文件系统中的可执行文件 使用type 来确定一个命令是否是内置命令: type 命令 通常来说&#xff0c;内置命令会比外部命令执行得更快: 执行外部命令时不但会触发磁盘 I/0&am…

MyBatis的核心技术掌握,简单易懂(上)

目录 一.MyBatis中的动态SQL 二.MyBatis中的模糊查询 1. # 符号 2. $ 符号 ---问题 ---所以大家知道 # 和 $ 在MyBatis中的模糊查询中的区别了嘛&#xff1f;&#xff1f; 三.MyBatis 中的结果映射 1. resultType&#xff1a; 2. resultMap&#xff1a; ---问题 ---…