Spring中的三级缓存和循环依赖

三级缓存

在 Spring 中,Bean 的创建过程涉及到三级缓存。这三级缓存分别是 singletonObjects、earlySingletonObjects 和 singletonFactories。它们在 Spring 容器启动时用于存储正在创建的 Bean 实例。

在 Spring 源码中,三级缓存涉及到了 DefaultSingletonBeanRegistry 类。这个类是 Spring 容器中负责管理单例 Bean 的注册表,其中包含了三级缓存的实现。下面是 DefaultSingletonBeanRegistry 中与三级缓存相关的源码片段:

public abstract class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {// 一级缓存:singletonObjectsprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:earlySingletonObjectsprivate final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三级缓存:singletonFactoriesprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);...protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 从一级缓存中获取 Bean 实例Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 从二级缓存中获取 Bean 实例singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 从三级缓存中获取 Bean 实例的 ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 使用 ObjectFactory 创建 Bean 实例singletonObject = singletonFactory.getObject();// 将创建好的 Bean 实例放入二级缓存中this.earlySingletonObjects.put(beanName, singletonObject);// 从三级缓存中移除 ObjectFactorythis.singletonFactories.remove(beanName);}}}}return singletonObject;}...}

DefaultSingletonBeanRegistry 类中,singletonObjects 用于存储已经完成初始化的 Bean 实例,earlySingletonObjects 用于存储尚未完成初始化的 Bean 实例,singletonFactories 用于存储创建 Bean 的工厂对象。在 getSingleton() 方法中,首先会尝试从一级缓存 singletonObjects 中获取 Bean 实例,如果找不到且 Bean 正在创建中,则会从二级缓存 earlySingletonObjects 中获取 Bean 实例,如果仍然找不到且允许早期引用,则会从三级缓存 singletonFactories 中获取 Bean 实例的工厂对象,并使用工厂对象创建 Bean 实例,然后将创建好的 Bean 实例放入二级缓存 earlySingletonObjects 中。

  1. singletonObjects:

    • 这是最常见的单例对象缓存。当容器创建 Bean 时,会首先尝试从 singletonObjects 缓存中获取已经创建好的 Bean 实例。
    • 如果能够从 singletonObjects 中获取到 Bean 实例,就直接返回该实例。
    • 如果 singletonObjects 缓存中不存在 Bean 实例,则继续后续的创建流程。
  2. earlySingletonObjects:

    • 这个缓存用于存储尚未完成初始化的早期单例对象。
    • 在创建 Bean 的过程中,如果发现 Bean 的初始化依赖其他 Bean,而这些依赖的 Bean 正好是单例的,则会暂时将正在创建的 Bean 实例放入 earlySingletonObjects 缓存中,以便解决循环依赖的问题。
    • 等到 Bean 的创建完成后,会将其移动到 singletonObjects 缓存中。
  3. singletonFactories:

    • 这个缓存用于存储创建 Bean 的工厂对象(ObjectFactory)。
    • 当 Bean 的创建过程中需要解决循环依赖时,会将创建 Bean 的工厂对象放入 singletonFactories 缓存中。
    • 当需要获取正在创建的 Bean 的依赖时,会从 singletonFactories 缓存中获取对应的工厂对象,然后通过工厂对象创建 Bean 的代理对象,并将代理对象放入 earlySingletonObjects 缓存中,以便解决循环依赖的问题。

这三级缓存在 Spring 容器启动时起到了至关重要的作用,它们协同工作以解决 Bean 的循环依赖问题,确保容器能够正确地创建和管理 Bean 实例。


循环依赖

循环依赖是指两个或多个 Bean 之间相互依赖形成的循环引用关系。在 Spring 中,循环依赖通常出现在以下场景中:

  1. 构造器注入循环依赖: 当两个或多个 Bean 在它们的构造器中相互依赖时,就会出现构造器注入的循环依赖。例如,BeanA 的构造器参数依赖于 BeanB,而 BeanB 的构造器参数又依赖于 BeanA。

  2. setter 方法注入循环依赖: 当两个或多个 Bean 在它们的 setter 方法中相互依赖时,就会出现 setter 方法注入的循环依赖。例如,BeanA 的某个属性依赖于 BeanB,而 BeanB 的某个属性又依赖于 BeanA。

为了解决循环依赖的问题,Spring 使用了三级缓存的机制。这个机制的原理如下:

  1. 当容器创建 Bean 的过程中,如果发现循环依赖,会将正在创建的 Bean 实例放入到早期单例对象的缓存中(即二级缓存 earlySingletonObjects)。

  2. 同时,为了解决循环依赖,会创建 Bean 的工厂对象(即 ObjectFactory),并将工厂对象放入到三级缓存 singletonFactories 中。

  3. 当需要解决循环依赖时,容器会从三级缓存 singletonFactories 中获取 Bean 的工厂对象,并使用工厂对象创建 Bean 的代理对象。

  4. 创建好的代理对象会被放入到二级缓存 earlySingletonObjects 中,以便在后续的 Bean 创建过程中能够获取到已经创建的 Bean 的代理对象。

  5. 当所有 Bean 都创建完成后,容器会再次遍历二级缓存 earlySingletonObjects 中的 Bean 实例,将它们初始化并放入一级缓存 singletonObjects 中。

通过三级缓存的机制,Spring 能够解决循环依赖的问题,确保容器能够正确地创建和管理 Bean 实例。这种机制下,即使存在循环依赖,也能够保证所有 Bean 都能够正确地初始化和注入依赖。

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

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

相关文章

python02 循环与容器

一、if的条件判断 1-1 if elif else 判断年龄属于哪个年龄段 # 判断学生 core input(请输入成绩) ​ if int(core) >90 :print(优秀) elif int(core) >70 and int(core) <90:print(中等) elif int(core) >60 and int(core) <70:print(及格) else:print(不及…

20240521在Ubuntu20.04下编译RK3588的IPC方案的编译环境问题makeinfo: not found

20240521在Ubuntu20.04下编译RK3588的IPC方案的编译环境问题makeinfo: not found 2024/5/21 20:52 viewproviewpro-ThinkBook-16-G5-IRH:~/RK3588_IPC_SDK$ sudo apt-get install texinfo viewproviewpro-ThinkBook-16-G5-IRH:~$ viewproviewpro-ThinkBook-16-G5-IRH:~$ md5su…

【Basic】Linux Labs

文章目录 前言一、Linux Labs二、知识点ssh介绍ssh的主要功能SSH的工作原理SSH的常见用法 解题感悟 前言 由于我参加了网络安全的比赛(被迫)… but我毛都不会&#xff0c;所以我只能临时抱佛脚… 顺便把学习的过程记录下来&#xff0c;欢迎收看小白0基础ctf踩坑分享 一、Linux…

【正点原子Linux连载】 第四十六章 M.2硬盘驱动实验摘自【正点原子】ATK-DLRK3568嵌入式Linux驱动开发指南

1&#xff09;实验平台&#xff1a;正点原子ATK-DLRK3568开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id731866264428 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/docs/boards/xiaoxitongban 第四十…

【selenium】自动化测试chrome webdriver驱动下载网址,V123版本以上

Hi&#xff0c;大家好&#xff0c;今天和大家分享下最新的selenium自动化测试&#xff0c;chrome浏览器驱动下载的最新地址 chrome webdriver下载网址&#xff0c;适用于浏览器版本V123以上

结构型模式 (Python版)

代理模式 from abc import ABC, abstractmethod# 买的行为&#xff08;抽象类&#xff09; class Buy(ABC):abstractmethoddef buy_ticket(self):pass# 男人&#xff08;具体类&#xff09; class Man(Buy):# 男人买票def buy_ticket(self):print("Man 买票成功&#xff…

【输入示例100,999 输出示例4】水仙花数

// “水仙花数”是指一个三位正整数&#xff0c;其各位上的数字的立方和等于该数本身。如:1^35^33^3153&#xff0c;因此153是一个水仙花数。输入两个三位正整数a和b(其中a<b)&#xff0c;求[a,b]范围内水仙花数的个数。 //输入示例100,999 //输出示例4 #include <stdio.…

AI爆文写作:如果你有一篇文章爆了,正确的做法是:自己抄袭自己,重复发,还可以继续爆!

爆款总是相似的&#xff0c;如果你有一篇文章爆了&#xff0c;正确的做法&#xff0c;就是重复发&#xff0c;让它继续爆下去。 以前我在小红书看到一个人&#xff0c;将一篇自己火的笔记&#xff0c;连续发了5次&#xff0c;每次点赞数据都不错。 公众号文章也是一样的。 我…

Gin与OpenAPI(Swagger)的使用

一、背景 1、swagger与openapi Swagger&#xff1a; 一种用于描述RESTFUL API的规范&#xff0c;它提供了一种简单的来描述API的请求和相应参数、错误码、返回数据类型等信息&#xff0c;是开发者可以方便了解API使用方式。 官网: https://swagger.io/ OpenAPI : 始于 …

gazebo仿真不起飞——QGC地面站查看下是否参数正确

检查方法&#xff1a;打开QGC地面站查看是否能够切入定点模式&#xff0c;不能的话查看定位数据来源参数

uniapp(微信小程序)退出小程序方法

一、描述 场景是&#xff1a;当用户不予授权的时候&#xff0c;不允许使用该小程序&#xff0c;在用户点击取消之后&#xff0c;应该关闭当前小程序&#xff0c;不让他继续使用。 二、代码 uni.exitMiniProgram({success: function() {console.log(退出小程序成功);},fail: …

鸿蒙HarmonyOS实战-Stage模型(信息传递载体Want)

&#x1f680;前言 应用中的信息传递是为了实现各种功能和交互。信息传递可以帮助用户和应用之间进行有效的沟通和交流。通过信息传递&#xff0c;应用可以向用户传递重要的消息、通知和提示&#xff0c;以提供及时的反馈和指导。同时&#xff0c;用户也可以通过信息传递向应用…

FPGA 第4章 摄像头Bayer转rgb

参考文献 彩色MT9V034摄像头 Bayer转rgb FPGA实现 https://www.cnblogs.com/hqz68/p/10413896.html 文章目录 前言Bayer转rgb算法解析 总结 前言 Bayer格式是相机内部的原始数据, 一般后缀名为.raw。 对于彩色图像,一般是三原色数据&#xff0c;rgb格式。但是摄像头一个像素…

【linux-IMX6ULL-LED字符驱动框架完善】

目录 1.简介&#xff12;.前置知识2.1 重要函数及结构体2.2 程序框架流程 3. 代码详解&#xff1a; 1.简介 在上节&#xff0c;我对linux-IMX6ULL-字符设备驱动简单框架实验进行了说明和构建&#xff0c;但是也存在几个问题&#xff1b; 需要手动指定设备号&#xff0c;不能自…

TCP 与 UDP

0. tcp 与 udp 的 异同特性 TCPUDPname传输控制协议用户数据报协议面向连接&#xff1f; 需要 传输数据前建立连接传输完毕后断开连接不需要可靠的传输数据&#xff1f; 可靠 有确认机制&#xff08;三次握手&#xff09; 有确认、窗口、重传、拥塞控制的机制保证数据可靠传输…

itertools拼装迭代器

itertools拼装迭代器 连接多个迭代器 内置的itertools模块有一些函数可以把多个迭代器连城一个使用。 chain chain可以把多个迭代器从头到尾连成一个迭代器。 import itertoolsit itertools.chain([1, 2, 3], [4, 5, 6]) print(list(it))>>> [1, 2, 3, 4, 5, 6]…

操作视频号小店,新手最关心的问题,一篇给你讲解清楚!

大家好&#xff0c;我是电商小V 新手去做视频号小店的时候&#xff0c;心里面一定是有很多疑问的&#xff0c;会反复咨询一些最关心的问题&#xff0c;因为他们要做好准备&#xff0c;以防后续做店过程中出现问题&#xff0c;其实新手关心的问题就那几个&#xff0c;咱们今天就…

C++贪心算法3

过河的最短时间 #include<bits/stdc.h> using namespace std; void f(int); int n; int main() {system("color 1");cin>>n;int a[10010];for(int i0;i<n;i){cin>>a[i];}sort(a0,an);int ta[1];int k1n-2;int k2n-1;while(true){int t1a[0]a[k…

springboot2+mybatis-plus+vue3创建入门小项目[学生管理系统]02[实战篇]

创建一个 vue 项目 创建这个新的文件夹 创建前端项目 eggbox 数据库 SQL CREATE DATABASE IF NOT EXISTS egg DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; USE egg;CREATE TABLE stu (id INT AUTO_INCREMENT, -- 自增主键name VARCHAR(64) NOT NULL, -- 非空姓名字段&a…

前端传参的三种方式

1、params 传参 参数拼接在地址 url 的后面给后台&#xff1b;地址栏中可见 案例1 地址栏&#xff1a;https://xxxxxxxx/admin/clues/detail?id558 接口代码&#xff1a; export function getClueDetail(query: any) {return request<clueItem>({url: /clues/detai…