Spring 的三级缓存机制

Spring 在处理 循环依赖 时使用了 三级缓存机制,这是 Singleton Bean 创建过程中为了解决循环依赖的一种策略。通过三级缓存,Spring 可以提前暴露未完全初始化的对象,避免循环依赖导致的无限递归错误。


1. 三级缓存的结构

Spring IOC 容器的 三级缓存分为以下三个部分:

  1. 一级缓存(singletonObjects)

    • 存储的是完全初始化完成的单例对象
    • 类型:ConcurrentHashMap<String, Object>
    • 用于直接获取初始化完成的 bean。
  2. 二级缓存(earlySingletonObjects)

    • 存储的是早期暴露的单例对象(已实例化但尚未完全初始化的 bean)。
    • 类型:ConcurrentHashMap<String, Object>
    • 用于解决部分场景下的循环依赖问题,避免不必要的代理创建。
  3. 三级缓存(singletonFactories)

    • 存储的是ObjectFactory(对象工厂),用于生成 bean 的代理或延迟引用。
    • 类型:ConcurrentHashMap<String, ObjectFactory<?>>
    • 用于在需要时生成早期对象的引用,并放入二级缓存。

2. 三级缓存的工作流程

当遇到循环依赖时,Spring 会按照以下步骤来创建和管理 bean:

  1. 检查一级缓存:

    • singletonObjects 中查找,如果找到,说明这个 bean 已完全初始化,直接返回。
  2. 检查二级缓存:

    • 如果一级缓存中没有,则从 earlySingletonObjects(二级缓存)中查找。
    • 如果找到,说明这个 bean 还没完全初始化,但可以提供引用,直接返回。
  3. 检查三级缓存:

    • 如果一级和二级缓存都没有,从 singletonFactories(三级缓存)中获取一个对象工厂,调用工厂方法创建早期引用,并放入二级缓存。
  4. 放入一级缓存:

    • 完成 bean 的初始化后,将最终的对象存入 singletonObjects(一级缓存),并从二级、三级缓存中移除。

3. 示例:如何解决循环依赖

假设存在以下两个类:AB,它们互相依赖。

class A {private B b;public A(B b) {this.b = b;}
}class B {private A a;public void setA(A a) {this.a = a;}
}

Spring 容器中创建这两个对象时,会出现循环依赖:

  1. Spring 尝试实例化 A,但 A 的构造器依赖 B
  2. 容器开始创建 B,但 BsetA() 方法又依赖 A
  3. 为了解决这个循环依赖问题,Spring 将未完全初始化的 A 的引用提前暴露到二级缓存中。
  4. 在创建 B 时,B 可以通过二级缓存获取 A 的引用,完成注入。
  5. 最终,AB 都完成初始化,并分别存入一级缓存。

4. 代码中的核心逻辑

Spring 的核心实现位于 DefaultSingletonBeanRegistry 类中。

  • 三级缓存的使用逻辑大致如下:
// 从一级缓存中获取 bean
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null) {// 如果一级缓存没有,则尝试从二级缓存获取singletonObject = earlySingletonObjects.get(beanName);if (singletonObject == null) {// 如果二级缓存也没有,则从三级缓存的 ObjectFactory 中获取ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 提前暴露到二级缓存中earlySingletonObjects.put(beanName, singletonObject);singletonFactories.remove(beanName);}}
}
return singletonObject;

5. 为什么需要三级缓存?

  • 三级缓存的作用: 提前暴露一个未完全初始化的对象(或其代理)引用,避免循环依赖导致的死锁问题。
  • 为什么不直接使用二级缓存?
    • 二级缓存只能存储已经创建出的对象引用,但某些代理对象需要延迟创建。三级缓存通过 对象工厂(ObjectFactory) 延迟创建这些代理,灵活性更高。

6. 适用场景与限制

  1. 适用于 Setter 注入:

    • Spring 通过三级缓存可以处理 Setter 注入 场景中的循环依赖。
  2. 不适用于构造注入:

    • 如果两个 bean 通过构造器相互依赖,Spring 无法通过三级缓存解决,因为构造器必须一次性注入所有依赖。

7. 总结

  • 一级缓存: 存储完全初始化的对象。
  • 二级缓存: 存储早期暴露的对象引用,用于解决循环依赖。
  • 三级缓存: 存储对象工厂,用于延迟创建代理对象,并转移到二级缓存中。

三级缓存机制帮助 Spring 处理 Setter 注入 引发的循环依赖问题,但对于 构造器注入 的循环依赖无能为力。

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

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

相关文章

开发规范 - mac系统1小时装机极速装机开发环境

idea 官网下载&#xff0c;然后想办法破解 idea必备配置 设置自动import IDEA插件安装 idea必备插件 maven helperlombokMybatisX jdk配置 jdk不用单配配置&#xff0c;在idea中&#xff0c;选择一个语言环境&#xff08;jdk8/jdk11/jdk17…&#xff09;,然后默认下载j…

php计算经纬度距离 及 某点是否在经纬度节点范围

js版 计算经纬度距离 及 某点是否在经纬度节点范围 本文档由 https://blog.csdn.net/AdminGuan/article/details/128118657 改版而来。 php 版 计算经纬度距离 及 某点是否在经纬度节点范围 public function index(){//1.计算两个点(经纬度)的距离$staVal [lng > 106.64…

unity学习笔记-Text mesh Pro

Text mesh Pro组件 组件使用的大致流程细节导入之后字体没有显示可能一可能二 注意事项 好久没更了…最近在学习使用别人的框架进行开发&#xff0c;坑也不少&#xff0c;不过学习到了很多设计思维。 言归正传。忘了是什么是时候的版本开始&#xff0c;unity多了这个组件&#…

K哥30个站点的逆向爬虫代码|pyexecjs库的基本使用

仓库地址&#xff1a;https://github.com/kgepachong/crawler/ 常见问题 JS 代码里引用了三个库&#xff0c;npm install 安装一下即可&#xff0c;如果安装了还提示找不到库&#xff0c;那就是路径问题&#xff0c;推荐在当前目录下执行命令安装&#xff0c;或者在 Python 代…

WPF入门_02依赖属性

1、依赖属性主要有以下三个优点 1)依赖属性加入了属性变化通知、限制、验证等功能。这样可以使我们更方便地实现应用,同时大大减少了代码量 2)节约内存:在WinForm中,每个UI控件的属性都赋予了初始值,这样每个相同的控件在内存中都会保存一份初始值。而WPF依赖属性很好地…

uiautomatorviewer安卓9以上正常使用及问题处理

一、安卓9以上使用uiautomatorviewer问题现象 打开Unexpected error while obtaining UI hierarchy 问题详情 Unexpected error while obtaining UI hierarchy java.lang.reflect.InvocationTargetException 二、问题处理 需要的是替换对应D:\software\android-sdk-windows…

Linux环境下Jmeter执行压测脚本

Linux环境下Jmeter执行压测脚本 前提官网下载Jmeter执行脚本 前提 注意&#xff1a;Jmeter的运行依赖Java环境 官网下载Jmeter 1、下载链接&#xff1a;https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.6.3.zip 2、解压 unzip apache-jmeter-5.6.3.zip 执行脚本…

洛谷刷题 P1003 [NOIP2011 提高组] 铺地毯

题目传送&#xff1a;P1003 [NOIP2011 提高组] 铺地毯 思路 该题主要考察模拟思想&#xff0c;可以用二维数组来模拟表示地面&#xff0c;每个坐标点记录其最上层地毯&#xff0c;然后每输入一张地毯数据就对地面相应坐标点进行修改&#xff0c;最后读取目标地点的状态&#…

python将照片集导出成视频

shigen坚持更新文章的博客写手&#xff0c;记录成长&#xff0c;分享认知&#xff0c;留住感动。个人IP&#xff1a;shigen 背景 一个安静的下午&#xff0c;看着电脑里乱七八糟的照片&#xff0c;有大有小&#xff0c;宽高不一&#xff0c;突然想找个方式把他们统一起来&…

PC企业微信自动回复,群发管理,定时发送,朋友圈

服务提供了丰富的API和SDK&#xff0c;可以在企微的功能之上进行应用开发和功能扩展 自建应用可以调用企微hook或协议提供的接口来实现数据交互&#xff0c;可以直接调用hook或协议接口提供的功能来进行消息的发送与接收、用户管理、应用管理等操作&#xff0c;通过接口可以实…

滚雪球学Redis[7.0讲]:Redis在Web应用中的会话管理:实现、优化与安全性!

全文目录&#xff1a; ☁️前言⛅️1. 在Web应用中使用Redis管理会话&#x1f567;️1.1 什么是会话管理&#xff1f;&#x1f550;️1.2 为什么选择Redis来管理会话&#xff1f;&#x1f55c;️1.3 示例&#xff1a;使用Redis实现会话管理&#x1f551;️代码示例&#x1f55d…

Vue前端预览docx文档

Vue前端预览docx文档 实现效果 vue代码 <el-dialog title"预览" :visible.sync"filePreview"><div ref"file"></div></el-dialog>引入依赖文件 官方文档地址 https://www.npmjs.com/package/docx-preview?activeTabre…

MacOS安装BurpSuite

文章目录 一、下载地址二、下载注册机三、安装教程四、启动burpsuit五、免责声明 一、下载地址 https://portswigger-cdn.net/burp/releases/download?productpro&version2024.7.1&typeMacOsx二、下载注册机 https://github.com/NepoloHebo/BurpSuite-BurpLoaderKey…

Java 多线程进阶:常见的锁策略/synchronized原理/CAS(更新中)

一.常见的锁策略 锁:非常广义的话题; synchronized:只是市面上五花八门的锁的其中一种典型的实现,Java内置的推荐使用的锁; (1)乐观锁 && 悲观锁 乐观锁:加锁的时候,假设出现锁冲突的概率不大;接下来围绕加锁要做的工作很少; 悲观锁:加锁的时候,假设出现锁冲突的概…

数据库中存储树状关系的数据

三张表的文字描述 表1&#xff1a;包含字段A1,字段A2,字段A3. 字段A1是主键 表2&#xff1a;包含字段B1&#xff0c;字段B2&#xff0c;字段A1 字段B1是主键&#xff0c;字段A1是其外键。 1个字段A1的值可以匹配多条表2的记录. 表3&#xff1a;包含字段C1&#xff0c;字段C2&am…

下午题数据库设计15分

一、考什么 题目会给场景&#xff0c;和数据库的设计过程&#xff0c;让你补充残缺的E-R图&#xff0c;关系模式&#xff0c;找主键外键。还有1-2分的随机题型。 二、答题技巧 熟练基本知识结合题干 三、例题

【OD】【E卷】【真题】【200分】项目排期(PythonJavaJavaScriptC++C)

题目描述 项目组共有N个开发人员&#xff0c;项目经理接到了M个独立的需求&#xff0c;每个需求的工作量不同&#xff0c;且每个需求只能由一个开发人员独立完成&#xff0c;不能多人合作。假定各个需求直接无任何先后依赖关系&#xff0c;请设计算法帮助项目经理进行工作安排…

构建高效在线考试平台:Spring Boot与JavaWeb的融合

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于JavaWeb技术的在线考试系统设计与实现…

python图片文件路径排序

解决用sord 排序文件路径乱序问题&#xff1a; image_files 是 图片文件路径列表[pythonProject/video2img/1.jpg,pythonProject/video2img/2.jpg,.......] image_files.sort(keylambda x: int(x.split(/)[-1].split(.)[0]))

颜廷利:东方智慧的现代诠释者

人文公社 2024年10月21日 东方智者颜廷利, 哲学思想论古今, 和善互爱满天下, 无私奉献情意深… 在当代哲学与文化交融的浪潮中,颜廷利以其深邃的东方智慧和对古今思想的独到见解,成为了一位备受瞩目的思想家。他不仅倡导和谐共处、互爱互助的理念,更以自身的行动践行着无私…