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,一经查实,立即删除!

相关文章

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

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

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

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

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

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

某行动态cookie反爬虫分析

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

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

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

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

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

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

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

docker安装nginx并配置SSL

1、拉取镜像 docker pull nginx2、启动nginx容器,复制一份默认配置文件出来 // 以nginx镜像为基础镜像创建一个名为nginx01的容器 docker run -d -p 80:80 --name nginx01 nginx创建成功后会看到nginx的欢迎页面 3、挂载nginx目录 拷贝nginx的配置信息到主机目录…

【图论】强连通分量

一.定义 强连通分量(Strongly Connected Components,简称SCC)是图论中的一个概念,用于描述有向图中的一组顶点,其中任意两个顶点之间都存在一条有向路径。换句话说,对于图中的任意两个顶点u和v,…

Python爬虫—破解JS加密的Cookie

前言 在进行网站数据爬取时,很多网站会使用JS加密来保护Cookie的安全性,而为了防止被网站反爬虫机制识别出来,我们通常需要使用代理IP来隐藏我们的真实IP地址。 本篇文章将介绍如何结合代理IP破解JS加密的Cookie,主要包括以下几个…

银河麒麟V10 QtCreator安装配置说明(断网离线)

文章目录 1.安装要求:2.安装Qt1.安装要求: 拥有Qt软件安装包qt5.12-arm链接:https://pan.baidu.com/s/1FJerT6SckfjABxAn60rsrA?pwd=mfi6 提取码:mfi6 2.安装Qt 1)拷贝Qt软件包qt5.12-arm至系统/home/kylin/桌面 2)安装Qt软件包 cd /home/kylin/qt5.12-arm/桌面 su…

Flutter:gsy_flutter_demo项目学习——布局切换动画、列表滑动监听、列表滑动到指定位置、高斯模糊

前言 gsy_flutter_demo是一个关于各种小案例和小问题的方案解决。项目是由flutter大佬恋猫de小郭维护的 项目地址:https://github.com/CarGuo/gsy_flutter_demo 感兴趣的可以看一下大佬的文章:Flutter完整开发实战详解系列,GSY Flutter 系…

非凸科技受邀参加中科大线上量化分享

7月30日,非凸科技受邀参加由中国科学技术大学管理学院学生会、超级量化共同组织的“打开量化私募的黑箱”线上活动,分享量化前沿以及求职经验,助力同学们拿到心仪的offer。 活动上,非凸科技量化策略负责人陆一洲从多个角度分享了如…

485modbus转profinet网关连三菱变频器modbus通讯触摸屏监控

本案例介绍了如何通过485modbus转profinet网关连接威纶通与三菱变频器进行modbus通讯。485modbus转profinet网关提供了可靠的连接方式,使用户能够轻松地将不同类型的设备连接到同一网络中。通过使用这种网关,用户可以有效地管理和监控设备,从…

【华秋干货铺】PCB布线技巧升级:高速信号篇

如下表所示,接口信号能工作在8Gbps及以上速率,由于速率很高,PCB布线设计要求会更严格,在前几篇关于PCB布线内容的基础上,还需要根据本篇内容的要求来进行PCB布线设计。 高速信号布线时尽量少打孔换层,换层优…

vue 3.0 + element-ui MessageBox弹出框的 让文本框显示文字 placeholder

inputPlaceholder:请填写理由, 方法实现如下: this.$prompt(, 是否确认?, { confirmButtonText: 确定, cancelButtonText: 取消, inputPlaceholder:请填写理由, }).then(({ value }) > { if(value null || value ""){ Message({message: 请填…

卷积神经网络【图解CNN】

文章目录 1.卷积运算2.池化3.全连接层 卷积神经网络可以看作一个函数或者黑箱,输入就是图片的像素阵列,输出就是这个图片是什么? 图片是X,那么就输出‘x’,图片是‘O’,那么就输出O; 在计算机眼中&#xff…

如何制作VR全景地图,VR全景地图可以用在哪些领域?

引言: 随着科技的迅速进步,虚拟现实(VR)技术正逐渐渗透到各个领域。VR全景地图作为其中的重要应用之一,为人们提供了身临其境的全新体验。 一.什么是VR全景地图? VR全景地图是一种利用虚拟现实技术&…

怎样做好字幕翻译服务?

我们知道,字幕泛指影视作品后期加工的文字,往往显示在电视、电影、舞台作品中。字幕翻译就是将外国影片配上本国字幕或者是将本国影片配上外国字幕。那么,字幕翻译的主要流程是什么,怎样做好字幕翻译服务? 据了解&…

企业既要用u盘又要防止u盘泄密怎么办?

企业在日常生产生活过程中,使用u盘交换数据是最企业最常用也是最便携的方式,但是在使用u盘的同时,也给企业的数据保密工作带来了很大的挑战,往往很多情况下企业的是通过u盘进行数据泄漏的。很多企业采用一刀切的方式,直…