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

Spring三级缓存解决循环依赖

Spring三级缓存解决循环依赖

一 Spring bean对象的生命周期

在这里插入图片描述

二 三级缓存解决循环依赖

  1. 实现原理解析
    spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决的,所说的缓存其实也就是三个Map
    在这里插入图片描述
    在这里插入图片描述
    先实例化的bean会通过ObjectFactory半成品提前暴露在三级缓存中
    在这里插入图片描述
    我们假设现在有这样的场景AService依赖BService,BService依赖AService

(1) AService首先实例化,实例化通过ObjectFactory半成品暴露在三级缓存中

(2)填充属性BService,发现BService还未进行过加载,就会先去加载BService

(3)再加载BService的过程中,实例化,也通过ObjectFactory半成品暴露在三级缓存

(4)填充属性AService的时候,这时候能够从三级缓存中拿到半成品的ObjectFactory
在这里插入图片描述
拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法,getEarlyBeanReference这个方法主要逻辑大概描述下如果bean被AOP切面代理则返回的是beanProxy对象,如果未被代理则返回的是原bean实例。

这时我们会发现能够拿到bean实例(属性未填充),然后从三级缓存移除,放到二级缓存earlySingletonObjects中,而此时B注入的是一个半成品的实例A对象,不过随着B初始化完成后,A会继续进行后续的初始化操作,最终B会注入的是一个完整的A实例,因为在内存中它们是同一个对象。

如果这个bean被AOP进行了切面代理,singleFactory.getObject()方法每次执行都会是一个新的代理对象,假设这里只有一级和三级缓存的话,我每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象,这是不行的,因为AService是单例的,所有这里我们要借助二级缓存来解决这个问题,将执行了singleFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象。

  1. 总结
    为了解决循环依赖问题,Spring采用三级缓存(Three-Level Cache)的机制。具体步骤如下:

(1) 创建对象并放入singletonObjects缓存:当创建一个Bean时,Spring会先尝试从singletonObjects缓存中获取该Bean实例,如果找到则直接返回。如果没有找到,则进入下一步。

(2)提前暴露对象:在创建Bean的过程中,当Spring发现存在循环依赖时,会先提前暴露正在创建的Bean,并将其放入earlySingletonObjects缓存中。这样可以避免后续循环依赖时的死锁情况。

(3)创建对象并完成依赖注入:Spring会继续创建当前Bean,并进行依赖注入。如果依赖中仍然存在循环依赖,Spring会使用ObjectFactory或Provider延迟注入依赖。这样可以确保所有的依赖都已经创建完成。

(4)添加到singletonObjects缓存:当Bean创建完成后,会将其放入singletonObjects缓存中,以供后续的依赖注入使用。

  1. 解决办法
    在Spring中,如果出现循环依赖问题,可以采取以下几种方式来解决:

(1)构造函数注入:使用构造函数注入代替字段注入或setter注入。通过将依赖关系作为构造函数的参数传递,而不是直接在类中定义成员变量,并确保依赖关系的顺序正确,可以避免循环依赖的问题。

(2)使用@Lazy注解:使用@Lazy注解延迟加载Bean。通过在循环依赖的其中一个Bean上添加@Lazy注解,使其延迟初始化,从而打破循环依赖的死锁情况。

(3)使用代理模式:当出现循环依赖时,可以通过使用代理模式来解决。Spring提供了两种类型的代理:JDK动态代理和CGLIB代理。可以根据具体情况选择合适的代理方式。

(4)使用Setter注入:将字段注入改为使用setter注入。通过在setter方法上使用@Autowired注解,显式地控制依赖关系的注入顺序,以避免循环依赖。

(5)重新设计代码结构:有时,循环依赖问题可能是由于类之间的紧密耦合导致的。在这种情况下,重新审视代码结构,将相关的功能进行合理划分,减少或消除循环依赖。

相关文章:

Spring三级缓存解决循环依赖

Spring三级缓存解决循环依赖 一 Spring bean对象的生命周期 二 三级缓存解决循环依赖 实现原理解析 spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决的,所说的缓存其实也就是三个Map 先实例化的bean会通过ObjectFactory半…...

Vscode自动移出不用的包

Vscode自动移出不用的包 在Vscode中删除不用的包、Vscode移出不用的包、Vscode移出不用的import包 设置 找到setting.json(在字体设置里面),添加如下配置 "editor.codeActionsOnSave": { "source.organizeImports": tru…...

leetcode做题笔记120. 三角形最小路径和

给定一个三角形 triangle ,找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一…...

weblogic/CVE-2018-2894文件上传漏洞复现

启动docker环境 查看帮助文档 环境启动后,访问http://your-ip:7001/console,即可看到后台登录页面。 执行docker-compose logs | grep password可查看管理员密码,管理员用户名为weblogic,密码为lFVAJ89F 登录后台页面,…...

windows10默认浏览器总是自动更改为Edge浏览器

在设置的默认应用设置中把默认浏览器改为chrome或其他之后他自动又会改回Edge。不得不说*软真的狗。 解决办法: 后来发现在Edge浏览器的设置中有这么一个选项,会很无耻的默认是Edge。把它关掉后重新设置就行了。...

系统架构设计师考试论文:论软件架构风格与应用

软件体系结构风格是描述某一特定应用领域中系统组织方式的惯用模式。体系结构风格定义一个系统家族,即一个体系结构定义一个词汇表和一纽约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。体系结构风格反…...

xss-labs靶场通关详解

文章目录 前言level1level2level3level4level5level6level7level8level9level10level11level12level13level14level15level16level17level18level19&level20 前言 赶着假期结尾的时候,赶紧给自己找点任务做。现在对xss还是一知半解,只是了解个大概&a…...

关于类和接口

类和接口的区别,去除语法层面,谈谈编程层面的意义。 设计原则SOLID: S:单一职责(SRP),Single Responsibility Principle O:开-闭原则(OCP),Open-Closed Principle L:里氏替换(LSP)&…...

网络安全社区与资源分享: 推荐网络安全社区、论坛、博客、培训资源等,帮助从业者拓展人脉和知识。

第一章:引言 在当今数字化的世界中,网络安全问题变得愈发突出。随着各种新型威胁的涌现,网络安全从业者面临着持续不断的挑战。然而,正是因为这些挑战,网络安全社区应运而生,成为从业者们互相交流、学习和…...

SAP MM学习笔记26- SAP中 振替转记(转移过账)和 在库转送(库存转储)5 - 总结

SAP 中在库移动 不仅有入库(GR),出库(GI),也可以是单纯内部的转记或转送。 1,振替转记(转移过账) 具体查看我之前的文章。 SAP MM学习笔记26- SAP中 振替转记&#xff…...

Stable Diffusion WebUI提示词Prompts常用推荐

在Stable Diffusion(以下简称SD)中,提示词是很重要的一部分,写好提示词就能让画图事半功倍,下面介绍一款好用的工具,能很程度上让你更轻松。 他就是sd-webui-prompt-all-in-one 下面将详细介绍的安装以及使用,后面将详细讲解提示词(Prompt)应该如何写提示词才能使画…...

Android 13 Ethernet变更

Android13 有线变更 以太网相关的功能在Android12 和13 网络部分变化是不大的,Android11 到Android 12 网络部分无论是代码存放目录和代码逻辑都是有较多修改的,主要包括以下几个部分 限制了设置有线网参数设置接口方法 新增有线网开启关闭接口方法 新…...

基于单片机的超声波语音测距系统

一、系统方案 超声波具有指向性强,能量消耗缓慢,在介质中传播的距离较远,因而超声波经常用于距离的测量,如测距仪和物位测量仪等都可以通过超声波来实现。利用超声波检测往往比较迅速、方便、计算简单、易于做到实时控制&#xff…...

算法系列-力扣876-求链表的中间节点

# 求链表中间节点,如果有两个中间节点取后面那个 链表定义 // lc codestart /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val val; } * …...

SpringBoot集成Redis、Redisson保姆教程【附源码】

1. SpringBoot集成Redis 关于Redis的安装,这里就不重复介绍了,需要的朋友可以看我之前的博文Redis多系统安装(Windows、Linux、Ubuntu) Redis原生命令大全,作者整理的很详细,大部分命令转化为java命令基本也是关键词 Redis 命令参考 接下来开始我们的正题,一起学习下…...

c++多线程中常用的使用方法

1)promise(保证)和future的联合使用&#xff0c;实现两个线程的数据传递 #include <iostream> #include<thread> #include<future>using namespace std;//promise用法&#xff1a;可以给线程一个值&#xff0c;而从另一个线程读出该值 // 实现了两个线程的数…...

【dart】dart基础学习使用(一):变量、操作符、注释和库操作

前言 学习dart语言。 注释 Dart 支持单行注释、多行注释和文档注释。 单行注释 单行注释以 // 开头。Dart 编译器将忽略从 // 到行尾之间的所有内容。 void main() {// 这是单行注释print(Welcome to my Llama farm!); }多行注释 多行注释以 /* 开始&#xff0c;以 / 结…...

element-plus 设置 el-date-picker 弹出框位置

前言 概述&#xff1a;el-date-picker 组件会自动根据空间范围进行选择比较好的弹出位置&#xff0c;但特定情况下&#xff0c;它自动计算出的弹出位置并不符合我们的实际需求&#xff0c;故需要我们手动设置。 存在的问题&#xff1a;element-plus 中 el-date-picker 文档中并…...

C++day7(auto关键字、lambda表达式、C++中的数据类型转换、C++标准模板库(STL)、list、文件操作)

一、Xmind整理&#xff1a; 关键词总结&#xff1a; 二、上课笔记整理&#xff1a; 1.auto关键字 #include <iostream>using namespace std;int fun(int a, int b, float *c, char d, double *e,int f) {return 12; }int main() {//定义一个函数指针&#xff0c;指向fu…...

纽扣电池/锂电池UN38.3安全检测报告

根据规章要求&#xff0c;航空公司和机场货物收运部门应对锂电池进行运输文件审查&#xff0c;重要的是每种型号的锂电池UN38.3安全检测报告。该报告可由的三方检测机构。如不能提供此项检测报告&#xff0c;将禁止锂电池进行航空运输. UN38.3包含产品&#xff1a;1、 锂电池2…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

Django RBAC项目后端实战 - 03 DRF权限控制实现

项目背景 在上一篇文章中&#xff0c;我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统&#xff0c;为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...