当前位置: 首页 > news >正文

Spring解决循环依赖的原理

通过将自己注入自己,使用代理对象调用add方法解决了事务失效问题,但是这样不会产生循环依赖吗?

在OrdersCreateServiceImpl 中注入的是OrdersCreateServiceImpl 的代理对象,并不是OrdersCreateServiceImpl 本身实例,构不成循环依赖。即使向OrdersCreateServiceImpl 注入的是本身实例也不会报错,Spring通过三级缓存解决循环依赖,会先向成员变量注入一个半成品实例,而后再完成初始化。

Spring通过三级缓存对Bean延迟初始化解决循环依赖。

具体如下:

  1. singletonObjects缓存:这是 Spring 容器用来缓存完全初始化好的单例 bean 实例的缓存。

  2. earlySingletonObjects缓存:这个缓存是用来保存被实例化但还未完全初始化的 bean (半成品)的引用。

  3. singletonFactories缓存:这个缓存保存的是用于创建 bean 实例的 ObjectFactory,用于支持循环依赖的延迟初始化。

Spring 通过这三级缓存的组合,来确保在循环依赖情况下,能够正常初始化 bean。当一个 bean 在初始化过程中需要依赖另一个还未初始化的 bean 时,Spring 会调用相应的 对象工厂来获取对应的 bean 半成品实例,这样就实现了循环依赖的延迟初始化。一旦 bean 初始化完成,它就会被移动到正式的单例缓存中。

对于通过构造方法注入导致循环依赖的在其中一个类的构造方法中使用@Lazy注解注入一个代理对象即可解决。

1. 三级缓存的工作机制

在 Spring 中,Bean 的创建过程分为实例化、填充属性(依赖注入)、初始化三个阶段。为了避免循环依赖的问题,Spring 设计了三级缓存来管理 Bean 的生命周期,确保在某些依赖未完全初始化时,能提供 Bean 的早期引用以打破依赖闭环。

Spring 的三级缓存包括:

1.1 一级缓存 (singletonObjects)

  • 描述: 这是 Spring 中的正式单例缓存,存放的是完全初始化完成的 Bean 实例。
  • 目的: 一旦 Bean 完全初始化,它就会被放入这个缓存,并从二级缓存和三级缓存中移除。

1.2 二级缓存 (earlySingletonObjects)

  • 描述: 存放的是那些已经实例化,但尚未进行属性填充和初始化的 Bean 实例(“半成品”)。
  • 目的: 当 Spring 需要早期引用时,直接从这个缓存中获取,还没完全初始化,但可以使用。

1.3 三级缓存 (singletonFactories)

  • 描述: 这里保存的是一个 ObjectFactory,用于在需要时生成一个 Bean 的早期引用(通常是通过 AOP 代理的方式)。
  • 目的: 当一个 Bean 正在实例化过程中,而另一个 Bean 需要它时,Spring 会通过工厂(ObjectFactory)来生成这个 Bean 的早期引用,支持延迟初始化。

2. 循环依赖的处理流程

假设在一个场景中有两个 Bean AB,它们通过属性互相依赖,即 A 依赖 BB 依赖 A。Spring 通过以下步骤解决这种循环依赖:

2.1 实例化 Bean A

  1. Spring 首先实例化 Bean A(构造方法调用),但还没有进行属性注入和初始化操作。
  2. 在此时,Spring 会将 A 的早期引用放入 三级缓存 singletonFactories 中。

2.2 实例化 Bean B

  1. 当 Spring 尝试实例化 A 时,发现 A 依赖于 B,于是开始实例化 B
  2. Spring 同样会把 B 的早期引用放入三级缓存,并开始初始化它。

2.3 解决 Bean A 的依赖

  1. 在填充 B 的依赖时,发现 B 需要 A,此时 Spring 发现 A 的实例还未完全初始化,但 A 已经存在于三级缓存中。
  2. Spring 从 三级缓存 中获取 A 的早期引用(这个引用还没有完全初始化,只是一个代理或者半成品对象),并注入到 B 中。

2.4 完成初始化

  1. 现在 B 已经实例化并注入了 A,然后继续完成 B 的剩余初始化(比如调用 @PostConstruct 或者初始化方法)。
  2. B 完全初始化后,Spring 将 B 的实例放入 一级缓存 中,并从 二级缓存三级缓存 中移除。
  3. 接着,Spring 回到 A,现在 B 已经完全初始化,并注入到了 A 中,A 可以继续完成自己的初始化。
  4. 最终,A 也被放入 一级缓存 中。

通过这种方式,Spring 使用 三级缓存 来解决在 Bean 初始化过程中的循环依赖问题。

3. 构造器注入的循环依赖问题

  • 问题: 上述三级缓存机制能够处理 setter 注入 的循环依赖,但对于 构造器注入 的循环依赖,Spring 无法通过缓存机制来解决。
  • 原因: 在构造器注入中,Bean 的所有依赖必须在构造器中完全提供,无法等到 Bean 部分构造完成后再注入其他依赖。
  • 解决方法:
    • 通过 @Lazy 注解来延迟注入 Bean。在构造器注入中,@Lazy 会使依赖项在使用时才被注入,而不是在构造时就立即初始化,这样可以打破循环依赖。

@Service
public class A {private final B b;@Autowiredpublic A(@Lazy B b) {  // 使用 @Lazy 延迟注入this.b = b;}
}@Service
public class B {private final A a;@Autowiredpublic B(A a) {this.a = a;}
}

相关文章:

Spring解决循环依赖的原理

通过将自己注入自己,使用代理对象调用add方法解决了事务失效问题,但是这样不会产生循环依赖吗? 在OrdersCreateServiceImpl 中注入的是OrdersCreateServiceImpl 的代理对象,并不是OrdersCreateServiceImpl 本身实例,构…...

Openal o1初探

9 月 13 日,OpenAI 正式公开一系列全新 AI 大模型,传说的“草莓”终于上线,但是正式命名不叫“草莓”,而是o1。 一、为什么叫o1 为什么取名叫o1,OpenAI是这么说的: For complex reasoning tasks this is…...

基于python+django+vue的学生成绩管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…...

mimd 公平收敛在相图中的细节

aimd 的收敛已经说腻了,我曾经画了好几次相图。有朋友希望我能画一个 mimd 相图,我就再画一个稍微详细的。 下面相图收敛到稳定点的前提异步 mimd: 之所以要异步,举个例子,在执行 gx 时,要确保 y 已经执…...

爬虫--翻页tips

免责声明:本文仅做分享! 伪线程 from DrissionPage import ChromiumPage import timepage ChromiumPage() page.get("https://you.ctrip.com/sight/taian746.html") # 初始化 第0页 index_page 0# 翻页点击函数 sleep def page_turn():page…...

论文内容分类与检测系统源码分享

论文内容分类与检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…...

【MySQL】将表导出CSV(可以使用excel打开)

1、准备工作 查看数据库: show databases;切换数据库: use 数据库名;查看表名字 show tables;2、单个表导出 需要替换导出csv文件目录和表名 SELECT * INTO OUTFILE 目录/文件名.csv FIELDS TERMINATED BY , ENCLOSED BY " LINES TERMINATED …...

通用四期ARM架构银河麒麟桌面操作系统V10【安装、配置FTP服务端】

一、操作环境 服务端:银河麒麟桌面操作系统V10SP1 (服务端包链接:https://download.csdn.net/download/AirIT/89747026) 客户端:银河麒麟桌面操作系统V10SP1 (客户端包链接:https://downloa…...

梧桐数据库(WuTongDB):RBO(Rule-Based Optimizer)优化器简介

RBO(Rule-Based Optimizer,基于规则的优化器) 是一种早期的数据库查询优化方法,它通过预定义的一组规则来决定查询的执行计划,而不是像 CBO(Cost-Based Optimizer,基于成本的优化器)…...

【农信网-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...

Gitea Action 简单配置(CI/CD)

线上pipeline,(我使用是本地仓库的,你们使用切换成官网的即可) # 工作流的名称name: Build and Push Docker Image deployment-k8s# 触发条件,只在 master 或 main 分支发送推送时触发 on:push:branches:- main# 作业&#xff0c…...

苍穹外卖 修改nginx的端口后websocket连接失败解决

苍穹外卖 修改nginx的端口后websocket连接失败解决 问题: 后端配置好websocket后前端仍显示如图所示的错误 解决: 先用websocket在线工具测试后端是否能正常连接(这个基本上不会出现问题)用f12观察前端发送的请求 正常来说这个请…...

快速解决Linux中wine程序中文显示为方块的问题

在home目录下Ctrlh 将显示.wine文件夹,把window系统中的C:\WINDOWS\Fonts文件夹直接copy到.wine/drive_c/windows 目录中并覆盖其Fonts目录即可。 参考链接: https://www.cnblogs.com/jee-cai/p/14095220.html https://blog.csdn.net/srz2017/article/…...

【C++前后缀分解 动态规划】2100. 适合野炊的日子|1702

本文涉及知道点 C前后缀分解 C动态规划 LeetCode2100. 适合野炊的日子 你和朋友们准备去野炊。给你一个下标从 0 开始的整数数组 security ,其中 security[i] 是第 i 天的建议出行指数。日子从 0 开始编号。同时给你一个整数 time 。 如果第 i 天满足以下所有条件…...

HarmonyOS 速记

目录 装饰器Entry(入口)Component(组件)State(状态)Preview(预览)PreviewerInspector 结构体structbuild自定义组件自定义 Custom 组件 容器Row(行) & Column(列)RelativeContainer(相对布局容器)marginpaddingGrid(网格容器)List(列表) 组件Image(图片)图片的填充模式 Tex…...

使用 Milvus、vLLM 和 Llama 3.1 搭建 RAG 应用

vLLM 是一个简单易用的 LLM 推理服务库。加州大学伯克利分校于 2024 年 7 月将 vLLM 作为孵化项目正式捐赠给 LF AI & Data Foundation 基金会。欢迎 vLLM 加入 LF AI & Data 大家庭!🎉 在主流的 AI 应用架构中,大语言模型&#xff0…...

【springboot】父子工程项目搭建

父工程创建 1.新建一个spring项目 2.选择合适的springboot版本,点击【完成】,即创建父工程完毕 3.删除父工程中无用文件:src 创建子工程模块 1.右键项目名->新建(news)->模块(Module)…...

【Paper Reading】结合 NanoFlow 研究,优化大语言模型服务效率的探索

作者 王伟 PAI引擎团队 近年来,人工智能领域的快速发展推动了大型语言模型的广泛应用,随之而来的是对其服务效率的迫切需求。论文《NanoFlow:Towards Optimal Large Language Model Serving Throughput》提出了一种突破性的新型服务框架&…...

达芬奇竖屏导出有黑屏解决方案

文章目录 项目设置导出设置 初学达芬奇,导出的时候,总是有黑边。 经过研究,才发现导出的时候的分辨率和项目分辨率 2个地方都要设置,否则导出就会导致有黑边。 项目设置 点击 文件 选择项目设置 选择竖屏分辨率 导出设置...

Elasticsearch Java API 针对 Geohash7 网点进行分桶聚合

需求整理: geohash 7网格存储工作热度和学习热度数值,支持随机区域多个范围的热度聚合; 创建索引结构 索引文档需要包含 Geohash 网格、工作热度和学习热度等字段。可以在 Elasticsearch 中定义一个索引,确保 location 字段的类…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

高分辨率图像合成归一化流扩展

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 1 摘要 我们提出了STARFlow&#xff0c;一种基于归一化流的可扩展生成模型&#xff0c;它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流&#xff08;TARFlow&am…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...

【Zephyr 系列 16】构建 BLE + LoRa 协同通信系统:网关转发与混合调度实战

🧠关键词:Zephyr、BLE、LoRa、混合通信、事件驱动、网关中继、低功耗调度 📌面向读者:希望将 BLE 和 LoRa 结合应用于资产追踪、环境监测、远程数据采集等场景的开发者 📊篇幅预计:5300+ 字 🧭 背景与需求 在许多 IoT 项目中,单一通信方式往往难以兼顾近场数据采集…...

Electron简介(附电子书学习资料)

一、什么是Electron&#xff1f; Electron 是一个由 GitHub 开发的 开源框架&#xff0c;允许开发者使用 Web技术&#xff08;HTML、CSS、JavaScript&#xff09; 构建跨平台的桌面应用程序&#xff08;Windows、macOS、Linux&#xff09;。它将 Chromium浏览器内核 和 Node.j…...

【Vue】scoped+组件通信+props校验

【scoped作用及原理】 【作用】 默认写在组件中style的样式会全局生效, 因此很容易造成多个组件之间的样式冲突问题 故而可以给组件加上scoped 属性&#xff0c; 令样式只作用于当前组件的标签 作用&#xff1a;防止不同vue组件样式污染 【原理】 给组件加上scoped 属性后…...

【系统架构设计师-2025上半年真题】综合知识-参考答案及部分详解(回忆版)

更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20~21题】【第…...