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

Spring 的循环依赖

在 Spring 中,循环依赖是指两个或多个 Bean 相互依赖,导致在创建过程中出现了依赖死锁的问题。为了解决循环依赖,Spring 引入了三级缓存机制。了解为什么需要三级缓存机制,首先要明白循环依赖是如何发生的,以及两级缓存为什么不足够。

一、循环依赖是什么?

假设有两个 Bean AB

  • A 依赖于 B
  • B 依赖于 A

如果没有缓存机制,Spring 在创建 A 时会发现它需要 B,于是去创建 B,但在创建 B 时又发现需要 A,这时就会产生循环依赖,最终导致栈溢出或抛出异常。

二、三级缓存机制

Spring 使用三级缓存(三级依赖处理机制)来解决循环依赖问题,分别是:

  1. 一级缓存singletonObjects,用于存储完全初始化好的单例对象。

    • 完全初始化后的 Bean 会放入一级缓存中,表示该 Bean 已经准备好可以使用了。
  2. 二级缓存earlySingletonObjects,用于存储提前暴露的 Bean,主要是尚未完成依赖注入但已经实例化的 Bean。

    • 这个缓存用于提前暴露尚未完成初始化的 Bean,防止循环依赖无法解决。通常情况下,如果某个 Bean 已经实例化但还没有完成后续的属性填充等操作,它会存放在这个缓存中。
  3. 三级缓存singletonFactories,用于存储 Bean 的 ObjectFactory(对象工厂),这个工厂提供对该 Bean 的代理对象(比如 AOP 代理对象)的创建逻辑。

    • 三级缓存的存在使得 Spring 可以在 Bean 创建的早期阶段将未完全初始化的 Bean 提供出来,尤其是代理对象。这样即使 Bean 还没有完成依赖注入,也能通过工厂获得它的一个早期引用。

三、为什么需要三级缓存?两级不行吗?

假如只使用一级缓存和二级缓存:

  • 一级缓存只存储已经完全初始化好的 Bean,显然无法解决循环依赖问题,因为 Bean 尚未完成初始化时无法放入一级缓存。
  • 二级缓存则存储提前暴露的 Bean,但这通常是直接的原始对象,而不是代理对象。如果应用了 AOP 或者需要创建代理对象的场景中,依赖的 Bean 如果在循环依赖中被提前暴露时,可能无法应用正确的代理。

三级缓存 允许通过 ObjectFactory 这种延迟加载的方式,在需要的时候创建早期引用,包括创建代理对象。这确保了即使在循环依赖中,Spring 也可以在合适的时间点创建完整的代理对象,而不是仅仅提供原始对象。

四、总结

三级缓存机制的关键点在于:

  • 二级缓存不能解决 Bean 代理的问题,特别是在涉及到 AOP 的情况下。
  • 三级缓存通过引入 ObjectFactory,可以确保在代理场景下也能处理循环依赖,提前暴露还未完全初始化的代理对象。

因此,两级缓存不足以解决所有循环依赖问题,特别是在涉及到代理对象的情况下,三级缓存的机制显得非常必要。

4o

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • MAC 地址简化概念(有线 MAC 地址、无线 MAC 地址、MAC 地址的随机化)
  • C++笔记---多态
  • 『功能项目』项目优化 - 框架加载资源【41】
  • 【计算机网络】HTTP相关问题与解答
  • ARM/Linux嵌入式面经(三五):诺瓦星云提前批
  • JavaScript高级——循环遍历加监听
  • 我的标志:奇特的头像
  • Error: ENOENT: no such file or directory, uv_cwd
  • jeesite支持db2数据库初始化sql
  • Ubuntu下安装最新版本Apache2文件服务器
  • 单片机带隙电压基准电路
  • 把设计模式用起来!(3)用不好模式?之时机不对
  • 如何用 OBProxy 实现 OceanBase 的最佳路由策略
  • 在linux注册服务并开机启动springboot程序
  • html+css+js网页设计 旅游 大理旅游7个页面
  • ES6指北【2】—— 箭头函数
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • JavaScript 一些 DOM 的知识点
  • JS变量作用域
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • MySQL的数据类型
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • Web Storage相关
  • 笨办法学C 练习34:动态数组
  • 排序(1):冒泡排序
  • 前端之React实战:创建跨平台的项目架构
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 入口文件开始,分析Vue源码实现
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 06-01 点餐小程序前台界面搭建
  • 阿里云服务器如何修改远程端口?
  • #Z0458. 树的中心2
  • (javascript)再说document.body.scrollTop的使用问题
  • (libusb) usb口自动刷新
  • (pycharm)安装python库函数Matplotlib步骤
  • (顶刊)一个基于分类代理模型的超多目标优化算法
  • (二)换源+apt-get基础配置+搜狗拼音
  • (附源码)springboot教学评价 毕业设计 641310
  • (三)SvelteKit教程:layout 文件
  • (一)VirtualBox安装增强功能
  • (译)2019年前端性能优化清单 — 下篇
  • (转) 深度模型优化性能 调参
  • **PHP分步表单提交思路(分页表单提交)
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .net程序集学习心得
  • .net开发日常笔记(持续更新)
  • .NET企业级应用架构设计系列之结尾篇
  • .Net实现SCrypt Hash加密
  • @Import注解详解