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;探讨工业数据驱…

反转链表(C++)

1、迭代法的一种写法 ListNode* reverse_linkList(ListNode* head){if(head nullptr || head->next nullptr) return head;ListNode* begin nullptr;ListNode* mid head;ListNode* end head->next;while(true){mid->next begin;if(end nullptr){break;}begin …

MySQL常用表级操作

基础信息相关 1.修改表名&#xff1a; rename table 旧表名 to 新表名; 2、修改字段类型&#xff1a; alter table 表名 modify column 字段名 字段类型(长度) 3、修改字段名称和类型&#xff1a; alter table 表名 change 现有字段名称 修改后字段名称 数据类型 4、增加字段&a…

《存储IO路径》专题:DDIO对系统性能的影响

DDIO对系统性的影响 想象一下,有一天,你在网上冲浪,突然,一个巨大的数据包从天而降,直接砸在了你的电脑上。你一看,哇,是全新的《英雄联盟》版本!你迫不及待地打开了游戏,发现加载速度简直快如闪电。 那么,这个神奇的事情是怎么发生的呢? 其实,这都要归功于DDIO技…

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天在优橙真实感受吧~…

四旋翼欧拉方程推导过程

四旋翼欧拉方程推导过程 目录 一、欧拉方程的推导过程二、向量叉乘和叉乘1、向量点乘(内积)2、向量叉乘(外积)3三、矩阵乘法1、矩阵点乘3、矩阵乘法一、欧拉方程的推导过程 (参考:https://www.zhihu.com/question/327324524) 根据定义,角动量的表达式为: H = I ⋅ …

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

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

C++学习笔记总结练习:nullptr、NULL、0

三者的区别 参考文献 区别 1 说明 C中的NULL C中使用 ((void*)0)表示空指针。NULL会被替换为 ((void*)0) int *i NULL; foo_t *f NULL;#define NULL ((void*)0)C中的NULL C中void* 不能进行强制类型转换成其他类型的NULL&#xff0c;所以int* 类型的空指针&#xff0c;不…

vue使用插件vue-seamless-scroll无限滚动列表

链接: vue-seamless-scroll插件文档 安装vue-seamless-scroll npm install vue-seamless-scroll --save引入 1、main.js全局引入 import scroll from vue-seamless-scroll Vue.use(scroll)2、局部引入 import vueSeamlessScroll from vue-seamless-scrollcomponents: {vueS…

【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;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失…

【Luogu】 P5769 [JSOI2016] 飞机调度

题目链接 点击打开链接 题目解法 考虑可以经停&#xff0c;从 i i i 到 j j j 包括维修在内的最短时间&#xff0c;这是可以通过 f l o y d O ( n 3 ) floyd\;O(n^3) floydO(n3) 求的 这样我们可以维护出一辆飞机是否可以先运行航班 x x x 再运行航班 y y y&#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]…

使用ChatGPT构建一个AIML聊天机器人是什么体验

​ 使用ChatGPT构建一个AIML聊天机器人是什么体验&#xff0c;使用ChatGPT将C#代码转换为Swift代码以实现Swift版的Aiml聊天机器人&#xff0c;AIML&#xff08;全名为Artificial Intelligence Markup Language&#xff09;是一种基于XML模式匹配的人工智能标记语言&#xff0c…

嵌入式学习之linux

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

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

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

如何通过以太坊JSON-RPC方式获取ERC-20代币的信息?

目录 一、ERC-20介绍 二、ERC-20代币标准功能 1、可选功能 2、标准功能 三、获取代币信息