解析Spring中的循环依赖问题:初探三级缓存

news2024/11/28 22:55:46

什么是循环依赖?

这个情况很简单,即A对象依赖B对象,同时B对象也依赖A对象,让我们来简单看一下。

// A依赖了B
class A{
 public B b;
}

// B依赖了A
class B{
 public A a;
}

这种循环依赖可能会引发问题吗?

在没有考虑Spring框架的情况下,循环依赖并不会带来问题,因为对象之间相互依赖是非常普遍且正常的现象。

比如

A a = new A();
B b = new B();

a.b = b;
b.a = a;

这样,A,B就依赖上了。

然而,在Spring框架中存在一个令人头疼的问题,即循环依赖,这一问题的根源是什么呢?

在Spring框架中,一个对象的实例化并非简单地通过new关键字完成,而是经历了一系列Bean生命周期的阶段。正是由于这种Bean的生命周期机制,才导致了循环依赖问题的出现。在Spring应用中,循环依赖问题是一个常见现象,有些情况下Spring框架能够自动解决这种问题,但在其他情况下,需要开发人员介入并进行手动解决。接下来将详细探讨这些情况。

要深入理解Spring中的循环依赖,首先需要对Spring中Bean的完整生命周期有所了解。在这里不会深入展开对Bean生命周期的详细描述,因为之前的文章已经单独探讨过这一话题。因此,这里将简要概述Bean生命周期的大致过程。

Spring 管理的对象称为 Bean,通过Spring的扫描机制获取到类的BeanDefinition后,接下来的流程是:

  1. 解析BeanDefinition以实例化Bean:
    a. 推断类的构造方法。
    b. 利用反射机制实例化对象(称为原始对象)。
  2. 填充原始对象的属性,实现依赖注入。
  3. 如果原始对象中的方法被AOP增强,生成代理对象:
    a. 根据原始对象生成代理对象。
  4. 将生成的代理对象存放到单例池(在源码中称为singletonObjects)中,以便下次直接获取。

这个过程简要描述了Spring容器在实例化Bean并处理AOP时的流程。

在Spring中,Bean的生成过程涉及多个复杂步骤,远不止上述简要提及的7个步骤。除了所列步骤外,还包括诸如Aware回调、初始化等繁琐流程,这些内容涉及的细节繁多,不在本文讨论范围。

在创建B类的Bean时,如果B类包含一个名为a的A类属性,那么在生成B的Bean时,需要确保A类的Bean已经存在。然而,由于B类Bean的创建条件是A类Bean的依赖注入过程,因此可能会导致循环依赖问题。这意味着在容器尝试实例化B类Bean时,它必须首先解决A类Bean的依赖关系,而A类Bean的实例化又依赖于B类Bean。所以这里就出现了循环依赖:

ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在创建过程中)

因此,这一系列问题最终导致无法成功创建ABean,进而也无法顺利创建BBean。

在这种循环依赖的情况下,正如前文所述,Spring通过一些机制来协助开发者解决部分循环依赖问题,这便是三级缓存。

三级缓存

在此简要介绍三级缓存的概念,随后在探讨AOP对象如何解决循环依赖问题时,将会对其进行更为详尽的回顾。

  • 在Spring框架中,单例对象缓存在singletonObjects中,其中存储的是已经经历了完整生命周期的bean对象。
  • earlySingletonObjects中的“early”一词表明其中缓存的是早期的bean对象。这里的“早期”指的是Bean的生命周期尚未完成,但已经将该Bean放入了earlySingletonObjects中。
  • singletonFactories中存储的是ObjectFactory,即对象工厂,用于创建早期bean对象的工厂。

在前文的分析中,我们得知产生循环依赖问题的主要原因是Bean之间相互依赖,导致在创建Bean时出现了循环引用的情况。主要是:

A创建时--->需要B---->B去创建--->需要A,从而产生了循环

image

因此,我们现在将深入探讨为何缓存机制能够成功解决这种循环依赖难题。那么,如何打破这一循环呢?我们可以引入一个中间层(缓存)来化解。

image

在A的Bean创建过程中,在执行依赖注入之前,首先将A的原始Bean提前放入缓存中,这样一来,其他Bean在需要时可以直接从缓存中获取,随后才进行依赖注入操作。

在这种情况下,当A的Bean依赖于B的Bean时,如果B的Bean尚不存在,则必须启动B的Bean创建流程。这一流程与A的Bean创建过程相似,首先生成B的原始对象,然后将其提前暴露并置入缓存中。

接着,在对B的原始对象执行依赖注入A操作时,此时可以从缓存中检索A的原始对象(尽管这仅为A的原始对象,尚非最终Bean状态)。当B的原始对象完成依赖注入后,B的生命周期随之终结,从而也促使A的生命周期得以顺利结束。

在整个流程中,只存在一个A原始对象,因此对于B而言,即使在属性注入阶段将A原始对象注入,也并不会有任何影响,因为A原始对象在随后的生命周期中保持不变,未在堆中发生任何变化。

总结

在文章中详细探讨了循环依赖问题及其解决思路分析,揭示了Spring所提供的Bean创建过程并非如我们所想象的那样简单。这一过程涉及众多复杂步骤,因此Spring引入了缓存机制,通过在后续阶段逐步维护堆中的初始对象,并逐步进行赋值来逐步完成Bean的创建。这种缓慢而谨慎的方式确保了Bean的正确创建。

然而,这种处理方式仅适用于普通对象的创建。我们了解到,Spring还涉及另一个重要特性,即面向切面编程(AOP)。根据这一逻辑,AOP代理对象可能会遇到一些问题,这将在接下来的章节中进行深入讨论。这也解释了为何Spring需要三级缓存而不仅仅是二级缓存的原因。

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

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

相关文章

信息系统项目管理师0097:价值交付系统(6项目管理概论—6.4价值驱动的项目管理知识体系—6.4.6价值交付系统)

点击查看专栏目录 文章目录 6.4.6价值交付系统1.创造价值2.价值交付组件3.信息流6.4.6价值交付系统 价值交付系统描述了项目如何在系统内运作,为组织及其干系人创造价值。价值交付系统包括项目如何创造价值、价值交付组件和信息流。 1.创造价值 项目存在于组织中,包括政府机构…

kkkkkkkkkkkk564

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习 📝人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

【LeetCode:LCR 077. 排序链表 + 链表】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

发表博客之:gemm/threadblock/threadblock_swizzle.h 文件夹讲解,cutlass深入讲解

文章目录 [发表博客之:gemm/threadblock/threadblock_swizzle.h 文件夹讲解,cutlass深入讲解](https://cyj666.blog.csdn.net/article/details/138514145)先来看一下最简单的struct GemmIdentityThreadblockSwizzle结构体 发表博客之:gemm/th…

STM32G030C8T6:EEPROM读写实验(I2C通信)

本专栏记录STM32开发各个功能的详细过程,方便自己后续查看,当然也供正在入门STM32单片机的兄弟们参考; 本小节的目标是,系统主频64 MHZ,采用高速外部晶振,实现PB11,PB10 引脚模拟I2C 时序,对M24C08 的EEPRO…

就业班 第三阶段(zabbix) 2401--5.9 day1 普通集zabbix 5.0部署 nginx部署+agent部署

文章目录 环境一、zabbix 5.0 部署1、安装yum源2、安装相关软件3、数据库安装和配置mariaDB数据库mysql57数据库 安装mysql万能卸载mysql代码:启动mysql并初始化4、数据表导入5、修改配置,启动服务6、配置 web GUI7、浏览器访问注意数据加密的选项不要勾…

基于Springboot的滴答拍摄影

基于SpringbootVue的滴答拍摄影设计与实现 开发语言:Java数据库:MySQL技术:SpringbootMybatis工具:IDEA、Maven、Navicat 系统展示 用户登录 首页 摄影作品 摄影服务 摄影论坛 后台登录 后台首页 用户管理 摄影师管理 摄影作…

谷歌继续将生成式人工智能融入网络安全

谷歌正在将多个威胁情报流与 Gemini 生成人工智能模型相结合,以创建新的云服务。 Google 威胁情报服务旨在帮助安全团队快速准确地整理大量数据,以便更好地保护组织免受网络攻击。 本周在旧金山举行的 RSA 会议上推出的 Google 威胁情报服务吸收了 Mand…

旅游组团奖励标准,申报条件!利川市旅游组团奖励办法

利川市旅游组团奖励有哪些?关于利川市旅游组团奖励标准,申报条件整理如下: 第一条根据《湖北省人民政府办公厅印发关于更好服务市场主体推动经济稳健发展若干政策措施的通知》(鄂政办发〔2022〕54号)、《恩施州人民政府…

力扣2105---给植物浇水II(Java、模拟、双指针)

题目描述: Alice 和 Bob 打算给花园里的 n 株植物浇水。植物排成一行,从左到右进行标记,编号从 0 到 n - 1 。其中,第 i 株植物的位置是 x i 。 每一株植物都需要浇特定量的水。Alice 和 Bob 每人有一个水罐,最初是…

Centos固定静态ip地址

这里我用的是Vmware虚拟机搭建的三台机器 进入 cd /etc/sysconfig/network-scripts然后使用 ip addr命令,查看自己虚拟机的以太网地址。 我这里是ens33 上面的第一个选项是本地环回地址,不用管它 然后查看刚刚进入的network-scripts目录下的文件 找到…

【机器学习】AI时代的核心驱动力

机器学习:AI时代的核心驱动力 一、引言二、机器学习的基本原理与应用三、机器学习算法概览四、代码实例:线性回归的Python实现 一、引言 在数字化浪潮席卷全球的今天,人工智能(AI)已经不再是科幻小说中的遥远概念&…

106短信平台疑难解答:为何手机正常却收不到短信?

当您使用群发短信平台发送消息时,有时尽管系统提示发送成功,但手机却未能收到短信。这背后可能隐藏着一些不为人知的原因。 首先,我们要明确,在正常情况下,只要手机状态正常,都应该能够接收到短信。然而&am…

图表控件LightningChart .NET中文教程 - 创建3D网格模型实时着色应用

LightningChart.NET完全由GPU加速,并且性能经过优化,可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D,高级3D,Polar,Smith,3D饼/甜甜圈,地理地图和GIS图表以及适用于科学…

【论文泛读|附源码】如何进行动力学重构? 神经网络自动编码器结合SINDy发现数据背后蕴含的方程

这一篇文章叫做 数据驱动的坐标发现与方程发现算法。 想回答的问题很简单,“如何根据数据写方程”。 想想牛顿的处境,如何根据各种不同物体下落的数据,写出万有引力的数学公式的。这篇文章就是来做这件事的。当然,这篇论文并没有…

远程连接阿里云ECS

说明:ECS(阿里云服务器)可选择的系统镜像如下: 本文介绍基于Windows系统,对CentOS、Ubuntu、Windows这三个操作系统的连接方式,以及连接工具Windterm的使用。 CentOS & Windterm CentOS是我使用时间最…

df 中的 NoneType、空和 None

哈喽,大家好,我是木头左! 目录 简介什么是 NoneType?什么是空(Empty)?什么是 None?Python 中如何判断 NoneType?Pandas DataFrame 中的 NoneType、空和 None实操&#x…

《红警OL》更换新东家,中国儒意收购有爱互娱全部股权

易采游戏网5月10日消息,近日港股上市公司中国儒意发布公告,宣布将以2.59亿人民币全资收购北京有爱互娱科技有限公司。此次收购的卖方为持股94.1047%的北京朝夕光年信息技术有限公司和持股5.8953%的北京游逸科技有限公司。这一消息在游戏行业引起了广泛关…

Github 2024-05-10 Java开源项目日报Top10

根据Github Trendings的统计,今日(2024-05-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目10C++项目2JavaGuide - Java 程序员学习和面试指南 创建周期:2118 天开发语言:Java协议类型:Apache License 2.0Star数量:140773 个…

Vue自定义封装音频播放组件(带拖拽进度条)

Vue自定义封装音频播放组件(带拖拽进度条) 描述 该款自定义组件可作为音频、视频播放的进度条,用于控制音频、视频的播放进度、暂停开始、拖拽进度条拓展性极高。 实现效果 具体效果可以根据自定义内容进行位置调整 项目需求 有播放暂停…