Spring 三级缓存机制(解决循环依赖)
文章目录
- 🔄 现实生活类比:开餐厅的过程
- 💡 结合到 Spring 三级缓存
- 🛠️ Spring 解决循环依赖的步骤
- 1️⃣ Spring 开始创建 A
- 2️⃣ Spring 开始创建 B
- 3️⃣ B 创建完成后,回过头来继续创建 A
- 📌 三级缓存的作用
- ❓ 为什么不用两级缓存,而要三级缓存?
- 🔚 结论
🔄 现实生活类比:开餐厅的过程
假设你是一个餐厅老板,你有两个大厨 A 和 B,他们互相配合做菜:
- A 需要 B 提供酱料
- B 需要 A 提供食材
- 但 A 和 B 都必须先开工,才能完成各自的任务。
如果他们都等对方的食材/酱料准备好,餐厅就会卡死,无法开张!(就像 Bean 创建时循环依赖)
于是,你(Spring 容器)设计了一个聪明的解决方案:
- 先让 A 和 B 都开始工作,即使他们还没完全准备好。
- 让他们先把“半成品”存放在一个共享架子上,这样可以让对方提前拿到需要的东西。
- 等到他们各自的任务完成后,再正式交付最终产品。
这个 共享架子,就是 Spring 三级缓存的核心机制!🔍
💡 结合到 Spring 三级缓存
现实餐厅 | Spring 三级缓存 |
---|---|
A 和 B 互相依赖,但必须同时开始工作 | A 依赖 B,B 依赖 A,必须同时创建 |
共享架子,存放半成品,方便对方使用 | 二级缓存(earlySingletonObjects),存放半成品 Bean |
如果需要特别处理(如食材加工),可以先放入工厂区 | 三级缓存(singletonFactories),存放 Bean 工厂 |
🛠️ Spring 解决循环依赖的步骤
假设 A 和 B 互相依赖(Setter 方式),Spring 解决循环依赖的过程如下:
1️⃣ Spring 开始创建 A
- 发现 A 依赖 B,于是暂停 A 的创建。
- 先把 A 的“工厂”(可以用来创建 A 的工具)放入
singletonFactories
(三级缓存)。
2️⃣ Spring 开始创建 B
- 发现 B 依赖 A,Spring 先去缓存里找 A。
- 此时 A 还没完全创建,但 Spring 可以从三级缓存里找到 A 的工厂,并提前创建 A 的半成品,然后存入
earlySingletonObjects
(二级缓存)。 - B 现在可以正常获取 A 了,继续完成 B 的创建。
3️⃣ B 创建完成后,回过头来继续创建 A
- A 依赖的 B 现在已经创建好了,A 终于可以完成创建,并存入
singletonObjects
(一级缓存)。 - B 也被放入一级缓存。
✅ 最终,A 和 B 都成功创建,没有死锁!
📌 三级缓存的作用
缓存 | 作用 | 何时使用 |
---|---|---|
一级缓存(singletonObjects) | 存放完全初始化的 Bean | Bean 创建完成后 |
二级缓存(earlySingletonObjects) | 存放提前暴露的半成品 Bean | 解决循环依赖时(但不支持代理) |
三级缓存(singletonFactories) | 存放Bean 创建工厂 | 用于创建代理对象(如 AOP) |
如果有 AOP 代理,Spring 会先从三级缓存拿出工厂,创建代理对象,再放入二级缓存,保证最终拿到的 Bean 是代理对象,而不是普通对象。
❓ 为什么不用两级缓存,而要三级缓存?
如果只用二级缓存(不使用三级缓存),会有什么问题?
-
无法支持 AOP 代理
。
- 代理对象是在Bean 创建完后才生成的,如果没有三级缓存,Spring 就没办法在 Bean 创建前插手进行代理。
- 三级缓存允许 Spring 在代理对象生成前,先存放一个“创建工厂”,让 Spring 可以决定是返回原始对象还是代理对象。
🔚 结论
- Spring 通过三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)来解决 Setter 方式的循环依赖。
- 一级缓存存放完全创建好的 Bean,二级缓存存放提前暴露的半成品,三级缓存存放 Bean 工厂(支持 AOP 代理)。
- 如果 Bean 需要 AOP 代理,Spring 先从三级缓存获取工厂,创建代理对象,然后存入二级缓存,最终返回代理对象。
- 构造器循环依赖无法通过三级缓存解决,因为 Spring 不能提前暴露半成品。
📌 总结一句话: Spring 通过共享“半成品”机制(三级缓存),让 A 和 B 在创建过程中互相提前看到对方,避免循环等待,从而成功创建!🎯
相关文章:
Spring 三级缓存机制(解决循环依赖)
文章目录 🔄 现实生活类比:开餐厅的过程💡 结合到 Spring 三级缓存🛠️ Spring 解决循环依赖的步骤1️⃣ Spring 开始创建 A2️⃣ Spring 开始创建 B3️⃣ B 创建完成后,回过头来继续创建 A 📌 三级缓存的作…...

第4章 4.4 EF Core数据库迁移 Add-Migration UpDate-Database
4.4.1 数据库迁移原理 总结一下就是: 1. 数据库迁移命令的执行,其实就是生成在数据库执行的脚本代码(两个文件:数字_迁移名.cs 数字_迁移名.Designer.cs),用于对数据库进行定义和修饰。 2. 数据库迁移…...
web安全——web应用程序技术
文章目录 一、HTTP1.1 HTTP方法1.2 HTTP消息头1.3 cookie1.4 状态码 二、web功能2.1 服务器端功能2.2 客户端功能——同源策略 三、编码方案3.1 URL编码3.2 Unicode编码3.3 HTML编码3.4 Base64编码 一、HTTP HTTP(超文本传输协议)是web应用程序使用的通…...

low rank decomposition如何用于矩阵的分解
1. 什么是矩阵分解和低秩分解 矩阵分解是将一个矩阵表示为若干结构更简单或具有特定性质的矩阵的组合或乘积的过程。低秩分解(Low Rank Decomposition)是其中一种方法,旨在将原矩阵近似为两个或多个秩较低的矩阵的乘积,从而降低复…...

GO 进行编译时插桩,实现零码注入
Go 编译时插桩 Go 语言的编译时插桩是一种在编译阶段自动注入监控代码的技术,目的是在不修改业务代码的情况下,实现对应用程序的监控和追踪。 基本原理 Go 编译时插桩的核心思想是通过在编译过程中对源代码进行分析和修改,将监控代码注入到…...
编写一个程序,输入一个字符串并输出其长度(Java版)
编写一个程序,输入一个字符串并输出其长度 以下是Java实现代码: import java.util.Scanner;public class StringLengthCalculator {public static void main(String[] args) {Scanner scanner new Scanner(System.in);System.out.print("请输入一…...
C++ day4 练习
一、练习1 找到第一天mystring练习,实现以下功能: mystring str "hello"; mystring ptr "world"; str str ptr; str ptr; str[0] H; 【代码】: #include <iostream> #include <cstring> #include &l…...
深入理解指针2
深入理解指针2 数组名的理解 数组名就是首元素的地址 int arr[]{1,3,2}; printf("%p\n",arr); printf("%p\n",&arr[0]);但是有两种情况除外, 1.sizeof(数组名),sizeof操作符统计的是整个数组的大小,并不是第一个元素…...

【STL专题】优先级队列priority_queue的使用和模拟实现,巧妙利用仿函数解决优先级
欢迎来到 CILMY23的博客 🏆本篇主题为:优先级队列priority_queue的使用和模拟实现,巧妙利用仿函数解决优先级 🏆个人主页:CILMY23-CSDN博客 🏆系列专栏: C | C语言 | 数据结构与算法 | Linux…...
CPU、SOC、MPU、MCU--详细分析四者的区别
一、CPU 与SOC的区别 1.CPU 对于电脑,我们经常提到,处理器,内存,显卡,硬盘四大部分可以组成一个基本的电脑。其中的处理器——Central Processing Unit(中央处理器)。CPU是一台计算机的运算核…...
Node.js 内置模块简介(带示例)
目录 1. fs(文件系统)模块 2. http 模块 3. path 模块 4. os 模块 5. events 模块 6. crypto 模块 1. fs(文件系统)模块 fs 模块提供了与文件系统进行交互的功能,包括文件的读写、删除、重命名等操作。它有同步…...
常见的“锁”有哪些?
悲观锁 悲观锁认为在并发环境中,数据随时可能被其他线程修改,因此在访问数据之前会先加锁,以防止其他线程对数据进行修改。常见的悲观锁实现有: 1.互斥锁 原理:互斥锁是一种最基本的锁类型,同一时间只允…...
二级公共基础之数据库设计基础(一) 数据库系统的基本概念
目录 前言 一、数据库、数据管理系统和数据库系统 1.数据 2.数据库 3.数据库管理系统 1.数据库管理系统的定义 2.数据库管理系统的功能 1.数据定义功能 2.数据操作功能 3.数据存取控制 4.数据完整性管理 5.数据备份和恢复 6.并发控制 4.数…...

ollama无法通过IP:11434访问
目录 1.介绍 2.直接在ollama的当前命令窗口中修改(法1) 3.更改ollama配置文件(法2) 3.1更新配置 3.2重启服务 1.介绍 ollama下载后默认情况下都是直接在本地的11434端口中运行,绑定到127.0.0.1(localhost)&#x…...
简单易懂,解析Go语言中的struct结构体
目录 4. struct 结构体4.1 初始化4.2 内嵌字段4.3 可见性4.4 方法与函数4.4.1 区别4.4.2 闭包 4.5 Tag 字段标签4.5.1定义4.5.2 Tag规范4.5.3 Tag意义 4. struct 结构体 go的结构体类似于其他语言中的class,主要区别就是go的结构体没有继承这一概念,但可…...

java给钉钉邮箱发送邮件
1.开通POP和IMAP 2.引入pom <dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version> </dependency>3.逻辑 String host "smtp.qiye.aliyun.com"; String port "…...

C++和OpenGL实现3D游戏编程【连载23】——几何着色器和法线可视化
欢迎来到zhooyu的C++和OpenGL游戏专栏,专栏连载的所有精彩内容目录详见下边链接: 🔥C++和OpenGL实现3D游戏编程【总览】 1、本节实现的内容 上一节课,我们在Blend软件中导出经纬球模型时,遇到了经纬球法线导致我们在游戏中模型光照显示问题,我们在Blender软件中可以通过…...

大连本地知识库的搭建--数据收集与预处理_01
1.马蜂窝爬虫 编程语言:Python爬虫框架:Selenium(用于浏览器自动化)解析库:BeautifulSoup(用于解析HTML) 2.爬虫策略 目标网站:马蜂窝(https://www.mafengwo.cn/&…...
github 推送的常见问题以及解决
文章目录 git add 的时候问题1为什么会发生这种情况?Git 的警告含义如何解决?1. **保持 Git 的默认行为(推荐)**2. **禁用自动转换**3. **仅在工作目录中禁用转换**4. **统一使用 LF(跨平台开发推荐)** git…...

stm32单片机个人学习笔记16(SPI通信协议)
前言 本篇文章属于stm32单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。 STM32入门教程-2023版 细…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...