Spring如何通过三级缓存解决循环依赖问题?

目录

一、什么是Spring

二、循环依赖问题

三、三级缓存机制

四、如何通过三级缓存解决循环依赖问题


 

一、什么是Spring

Spring框架是一个开源的Java应用程序开发框架,提供了一种全面的、一致的编程模型,用于构建企业级应用程序和服务。它由Rod Johnson在2003年创建,旨在简化Java开发并促进松耦合、可维护性和可扩展性。

Spring框架的核心特性包括: 1.控制反转(IoC):通过IoC容器管理对象之间的依赖关系,降低了组件之间的耦合度,使得应用程序更加灵活和可测试。 2.面向切面编程(AOP):通过AOP模块,可以将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,使得代码更加模块化和可维护。 3.数据访问和集成:Spring提供了灵活的数据访问和集成支持,包括对关系型数据库、NoSQL数据库、消息队列、缓存等的支持。 4.Web开发:Spring框架提供了Spring MVC模块,用于构建Web应用程序。它基于MVC设计模式,提供了灵活的配置和处理请求的能力。 5.事务管理:Spring框架支持声明式事务管理,通过配置来管理事务的边界和传播规则,简化了事务管理的编程工作。 6.安全性:Spring框架提供了一套安全性框架,用于认证和授权管理,保护应用程序的安全性。 7.测试支持:Spring框架提供了广泛的测试支持,包括对单元测试、集成测试和端到端测试的支持,使得开发人员能够更轻松地编写和运行测试用例。

Spring框架的设计理念是轻量级、可扩展和可插拔的,它被广泛应用于Java企业级开发中,是目前最受欢迎的Java开发框架之一。

 

二、循环依赖问题

Spring的循环依赖问题指的是在使用Spring的IoC容器进行对象创建和依赖注入时,如果存在循环依赖关系,则可能导致创建对象的过程无法完成或出现错误。

循环依赖是指两个或多个Bean之间相互依赖,形成一个循环链条。当A依赖B,B又依赖A时,就会产生循环依赖。

Spring在处理循环依赖时使用了三级缓存(singletonFactories、earlySingletonObjects和singletonObjects)来解决问题。具体的解决过程如下:

  1. 首先,当创建一个Bean时,Spring将该Bean放入singletonFactories缓存中。

  2. 如果Bean的创建过程中需要依赖其他Bean,Spring会通过递归调用创建所需的其他Bean。

  3. 当创建另一个Bean时,如果发现该Bean已经在singletonFactories缓存中,说明发生了循环依赖。

  4. 在这种情况下,Spring会尝试从earlySingletonObjects缓存中获取Bean的早期实例,如果存在,则返回该实例,否则继续创建Bean。

  5. 如果在创建Bean的过程中依然无法解决循环依赖问题,Spring会抛出BeanCurrentlyInCreationException异常,表示无法完成Bean的创建。

为了避免循环依赖问题,可以考虑以下几种方式:

  1. 通过构造函数注入:使用构造函数注入依赖,而不是使用Setter方法注入依赖。

  2. 使用Lazy注解:使用@Lazy注解延迟初始化Bean,以避免过早创建循环依赖的Bean。

  3. 使用Setter方法注入:将依赖注入改为Setter方法注入,并使用@Autowired注解。

  4. 使用@PostConstruct注解:使用@PostConstruct注解在Bean创建完成后执行一些初始化操作。

需要注意的是,虽然Spring提供了解决循环依赖的机制,但是过多的循环依赖可能会导致性能下降和代码的可读性下降,因此在设计应用程序时,应尽量避免出现循环依赖的情况。

 

三、三级缓存机制

Spring的三级缓存机制是为了解决循环依赖问题而设计的。当使用Spring的IoC容器创建对象时,会经过三个缓存级别来解决循环依赖问题。

  1. singletonFactories缓存:在对象创建过程中,如果发现循环依赖,Spring会将正在创建的Bean放入singletonFactories缓存中。这个缓存中存放的是对象的提供者,也就是用来创建Bean的工厂。

  2. earlySingletonObjects缓存:如果在创建Bean的过程中,发现依赖的Bean已经在singletonFactories缓存中,说明发生了循环依赖。此时,Spring会尝试从earlySingletonObjects缓存中获取Bean的早期实例(还未完全初始化),以解决循环依赖问题。

  3. singletonObjects缓存:如果无法从earlySingletonObjects缓存中获取到早期实例,Spring会将Bean放入singletonObjects缓存中,用于存放完全初始化后的Bean。

三级缓存的工作流程如下:

  1. 当创建Bean时,首先会检查singletonFactories缓存,如果发现正在创建的Bean已经在缓存中,则说明发生了循环依赖。

  2. 在循环依赖的情况下,会尝试从earlySingletonObjects缓存中获取早期实例,如果成功获取到早期实例,则返回该实例,解决了循环依赖问题。

  3. 如果无法从earlySingletonObjects缓存中获取早期实例,表示无法解决循环依赖,Spring会抛出BeanCurrentlyInCreationException异常。

  4. 如果解决了循环依赖,Bean会继续完成创建过程,并最终放入singletonObjects缓存中,供其他Bean使用。

通过三级缓存机制,Spring能够解决大部分的循环依赖问题,并确保Bean的创建和注入顺利进行。但需要注意的是,过多的循环依赖会增加系统的复杂性和性能开销,因此在设计应用程序时,应尽量避免循环依赖的出现。

以下是一个简单的Java样例代码,演示了Spring的三级缓存机制的实现:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
​
@Component
@Scope("singleton")
public class BeanA {
​private BeanB beanB;
​@Autowiredpublic BeanA(BeanB beanB) {this.beanB = beanB;}
​public void doSomething() {System.out.println("BeanA is doing something");beanB.doSomething();}
}
​
@Component
@Scope("singleton")
public class BeanB {
​private BeanA beanA;
​@Autowiredpublic BeanB(BeanA beanA) {this.beanA = beanA;}
​public void doSomething() {System.out.println("BeanB is doing something");beanA.doSomething();}
}
​
public class MainApp {
​public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);BeanA beanA = context.getBean(BeanA.class);beanA.doSomething();}
}

 

在上面的代码中,BeanABeanB互相依赖。当BeanA创建时,它依赖于BeanB。当BeanB创建时,它又依赖于BeanA。在MainApp中,通过ApplicationContext获取BeanA的实例,并调用doSomething方法。Spring会自动处理循环依赖关系,通过三级缓存机制确保BeanABeanB成功创建和注入。

需要注意的是,上述代码中使用了注解驱动的配置方式,通过@Component注解将Bean注册到Spring容器中,使用@Autowired注解进行依赖注入。此外,可以通过@Scope注解指定Bean的作用域为singleton,这是默认的作用域,也是三级缓存机制生效的前提。

四、如何通过三级缓存解决循环依赖问题

Spring通过三级缓存来解决循环依赖问题的具体步骤如下:

  1. 创建Bean A,将该Bean放入singletonFactories缓存中。

  2. 当创建Bean A的过程中发现它需要依赖Bean B,Spring会先检查singletonObjects缓存中是否存在Bean B的实例。

  3. 如果singletonObjects缓存中存在Bean B的实例,说明Bean B已经创建完成,可以直接将其注入到Bean A中。

  4. 如果singletonObjects缓存中不存在Bean B的实例,Spring会检查singletonFactories缓存中是否存在Bean B的提供者(即用来创建Bean B的工厂)。

  5. 如果singletonFactories缓存中存在Bean B的提供者,说明Bean B正在创建过程中,但尚未创建完成。此时,Spring会将正在创建的Bean A放入earlySingletonObjects缓存中,表示Bean A的早期实例。

  6. Spring继续创建Bean B,当Bean B创建完成后,会将其放入singletonObjects缓存中,并从earlySingletonObjects缓存中获取Bean A的早期实例。

  7. Bean A和Bean B创建完成后,Spring会完成Bean A的注入操作,将Bean B注入到Bean A中。

通过这样的三级缓存机制,Spring能够解决循环依赖的问题。当发生循环依赖时,早期实例的缓存earlySingletonObjects起到了临时存储的作用,保证了循环依赖的对象能够正确创建和注入。但需要注意的是,过多的循环依赖会增加系统的复杂性和性能开销,因此在设计应用程序时,应尽量避免循环依赖的出现。

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

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

相关文章

多个List 合并变成一个List+一个List 根据某个字段相等的另一个字段相加,并排序变成新的List

List<CurveTimeAndValueDomain> curves new ArrayList<>();for (int i 0; i < columnNames.size(); i){if (columnNames.get(i).equals(PlantConstant.TENDOWNFX) || columnNames.get(i).equals(PlantConstant.TENDOWNQP)) {//10千伏以下 数据 进行缓慢处理cu…

代码随想录算法训练营第五十三天 | 1143.最长公共子序列、1035.不相交的线、53.最大子数组和

文章目录 一、1143.最长公共子序列二、1035.不相交的线三、最大子数组和 一、1143.最长公共子序列 题目链接 代码如下&#xff1a; class Solution { public:int longestCommonSubsequence(string text1, string text2) {vector<vector<int>> dp (text1.size() …

Stable Diffusion中人物生成相关的negative prompts

下面是常用的negative prompt&#xff0c;在使用stable Diffusion webui等工具生成时可以填入。 bad anatomy, bad proportions, blurry, cloned face, deformed, disfigured, duplicate, extra arms, extra fingers, extra limbs, extra legs, fused fingers, gross proporti…

深度学习(32)——CycleGAN(1)

深度学习&#xff08;32&#xff09;——CycleGAN&#xff08;1&#xff09; 文章目录 深度学习&#xff08;32&#xff09;——CycleGAN&#xff08;1&#xff09;1. GAN原理2. CycleGAN&#xff08;1&#xff09;原理&#xff08;2&#xff09;核心思想&#xff08;3&#xf…

git回退到指定版本

#首先使用该方法查看版本号&#xff0c;后面可以接-n,n为数量&#xff0c;指定展示前几个版本记录。 git log &#xff08;或 git reflog&#xff09;#xxx换成你想回退的版本号。 git reset --hard xxx#强制推送到远程仓库&#xff0c;让远程仓库版本号一致。 git push origin…

PtahDAO:全球首个DAO治理资产信托计划的金融平台

金融科技是当今世界最具创新力和影响力的领域之一&#xff0c;区块链技术作为金融科技的核心驱动力&#xff0c;正在颠覆传统的金融模式&#xff0c;为全球用户提供更加普惠、便捷、安全的金融服务。在这个变革的浪潮中&#xff0c;PtahDAO&#xff08;普塔道&#xff09;作为全…

优漫动游|前端程序员容易出错的基础知识

web全栈是目前比较流行的语言&#xff0c;因为前端较其他语言相比&#xff0c;简单好学&#xff0c;而且现在的互联网公司几乎缺不了web前端开发&#xff0c;行业的需求致使大量的人转型前端&#xff0c;对于刚学前端的同学来讲&#xff0c;他们缺乏开发经验&#xff0c;在项目…

【C++】类与对象(2)

文章目录 前言一、类的6个默认成员函数二、构造函数1.概念2.特性3.初始化列表 三、析构函数1.概念2.特性 四、拷贝构造函数1.概念2.特性 五、赋值运算符重载1.运算符重载2.赋值运算符重载3.前置和后置重载 六、取地址及const取地址操作符重载总结 前言 在前面&#xff0c;给大…

【题解】单链表的排序

单链表的排序 题目链接&#xff1a;单链表的排序 解题思路1&#xff1a;分治、双指针 分治就是分而治之的意思&#xff0c;分的意思是说将一个大且复杂的问题划分成多个性质相似但是规模更小的问题&#xff0c;子问题继续按照同样的思路进行划分&#xff0c;直到问题被划分为…

【C++】开源:matplotlib-cpp静态图表库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍matplotlib-cpp图表库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

DC.js教程_编程入门自学教程_菜鸟教程-免费教程分享

教程简介 DC.js 是一个优秀的 JavaScript 库&#xff0c;用于在浏览器、移动设备中进行数据分析&#xff0c;最终有助于创建数据可视化&#xff1b;DC.js 是一个用于探索大型多维数据集的图表库&#xff0c;它依靠 D3.js 引擎以 CSS 友好的 SVG 格式呈现图表。它允许呈现复杂的…

ES6 - 数组新增的一些常用方法

文章目录 1&#xff0c;Array.from()2&#xff0c;Array.of()3&#xff0c;find()&#xff0c;findIndex()&#xff0c;findLast()和findLastIndex()4&#xff0c;Array.fill()5&#xff0c;keys()&#xff0c;values() 和 entries()6&#xff0c;Array.includes()7&#xff0c…

flask-----请求和响应,session

1 所有web:请求对象&#xff0c;响应对象(go,java,ptyhon) django&#xff1a;request&#xff08;每个请求一个request&#xff09;&#xff0c;新手四件套 flask&#xff1a;requset&#xff1a;全局的&#xff0c;但是也是每个请求一个request&#xff0c;新手三件套 2 fl…

【uniapp 报错 Cannot read properties of null (reading ‘offsetWidth‘)解决办法】

该错误通常是由于访问了一个空值的offsetWidth而引起的。解决方法如下&#xff1a; 检查代码中是否有访问了空值的情况&#xff0c;比如变量未初始化或者传入了空值参数或者事件未定义。 在操作元素之前&#xff0c;确保元素已经被正确加载。可以使用如下方法&#xff1a; <…

解决vue-print-nb-jeecg打印el-table表格预览竖版显示不全的问题!

第一步: 下载 vue-print-nb-jeecg 插件 npm install vue-print-nb-jeecg –save第二步: 在main.js中,引用并注册全局使用 import Print from vue-print-nb-jeecg Vue.use(Print);第三步: 需要打印的元素添加 id <div id"printMe">xxxx内容</div>第四步…

某行动态cookie反爬虫分析

某行动态cookie反爬虫分析 1. 预览 反爬网址(base64): aHR0cDovL3d3dy5wYmMuZ292LmNu 反爬截图&#xff1a; 需要先加载运行js代码&#xff0c;可能是对环境进行检测&#xff0c;反调试之类的 无限debugger 处理办法 网上大部分人说的都是添加cookie来解决。 那个noscript…

友盟+、GrowingIO和神策数据 对比

对于市面上的数据平台&#xff0c;先简单归个类。 1、移动统计平台&#xff0c;如友盟、talkingdata、百度云统计、腾讯移动应用统计等。 相同点是数据源都是埋点数据。友盟有免费版本。 前端效果&#xff1a;展现形式上为BI报表。 常用操作是页面内点击和筛选。 使用要求…

could not import go.etcd.io/etcd/clientv3-go

问题描述 今天在封装etcd的时候导包报错: could not import go.etcd.io/etcd/clientv3 (no required module provides package "go.etcd.io/etcd/clientv3") 问题解决: get:确保下载了client包 go get go.etcd.io/etcd/client tidy go mod tidy 本文由 mdnice 多平台…

yolov8-制作数据集,数据集格式转换(yolo格式-voc格式)附完整代码

yolo训练时可使用的数据集格式为yolo格式以及voc格式&#xff0c; voc格式的数据集在训练时需要先转换为yolo格式&#xff0c;然后根据自己的数据集的位置更改yaml配置文件的文件路径即可。基于目前对Yolo系列训练模型的讲解已经很全面&#xff0c;所以本文主要讲解yolo数据集与…

C#中 使用yield return 优化大数组或集合的访问

概要 我们在开发过程中&#xff0c;经常需要在一个很大的数组或集合中搜索元素&#xff0c;以满足业务需求。 本文主要介绍通过使用yield return的方式&#xff0c;避免将大量数据全部加载进入内存&#xff0c;再进行处理。从而提高程序的性能。 设计和实现 基本业务场景&a…