6 Spring循环依赖

什么是循环依赖?

// A依赖了B
class A{
public B b;
}
// B依赖了A
class B{
public A a;
}

如果不考虑Spring,循环依赖并不是问题,因为对象之间相互依赖是很正常的事情

A a = new A();
B b = new B();
a.b = b;
b.a = a;

        这样,A,B就依赖上了
        但是,在Spring中循环依赖就是一个问题了,为什么? 因为,在Spring中,一个对象并不是简单new出来了,而是会经过一系列的Bean的生命周期,就是因为Bean的生命周期所以才会出现循环依赖问题。当然,在Spring中,出现循环依赖的场景很多,有的场景Spring自动帮我们解决了,而有的场景则需要程序员来解决,下文详细来说。
        要明白Spring中的循环依赖,得先明白Spring中Bean的生命周期

Bean的生命周期

Bean的生命周期指的就是:在Spring中,Bean是如何生成的?
        被Spring管理的对象叫做Bean。Bean的生成步骤如下:
                1. Spring扫描class得到BeanDefinition
                2. 根据得到的BeanDefinition去生成bean
                3. 首先根据class推断构造方法
                4. 根据推断出来的构造方法,反射,得到一个对象(暂时叫做原始对象)
                5. 填充原始对象中的属性(依赖注入)
                6. 如果原始对象中的某个方法被AOP了,那么则需要根据原始对象生成一个代理对象
                7. 把最终生成的代理对象放入单例池(源码中叫做singletonObjects)中,下次getBean时就直接从单例池拿即可可以看到,对于Spring中的Bean的生成过程,步骤还是很多的,并且不仅仅只有上面的7步,还有很多很多,比如Aware回调、初始化等等


        可以发现,在Spring中,构造一个Bean,包括了new这个步骤(第4步构造方法反射)。
        得到一个原始对象后,Spring需要给对象中的属性进行依赖注入,那么这个注入过程是怎样的?
        比如上文说的A类,A类中存在一个B类的b属性,所以,当A类生成了一个原始对象之后,就会去给b属性去赋值,此时就会根据b属性的类型和属性名去BeanFactory中去获取B类所对应的单例bean。
        如果此时BeanFactory中存在B对应的Bean,那么直接拿来赋值给b属性;如果此时BeanFactory中不存在B对应的Bean,则需要生成一个B对应的Bean,然后赋值给b属性。
问题就出现在第二种情况,如果此时B类在BeanFactory中还没有生成对应的Bean,那么就需要去生成,就会经过B的Bean的生命周期。
        那么在创建B类的Bean的过程中,如果B类中存在一个A类的a属性,那么在创建B的Bean的过程中就需要A类对应的Bean,但是,触发B类Bean的创建的条件是A类Bean在创建过程中的依赖注入,所以这里就出现了循环依赖:
        ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在创建过程中)
        从而导致ABean创建不出来,BBean也创建不出来。

        这是循环依赖的场景,但是上文说了,在Spring中,通过某些机制帮开发者解决了部分循环依赖的问题,这个机制就是三级缓存

三级缓存

        三级缓存是通用的叫法

                一级缓存为:singletonObjects

                二级缓存为:earlySingletonObjects

                三级缓存为:singletonFactories

先稍微解释一下这三个缓存的作用,后面详细分析:
        singletonObjects中缓存的是已经经历了完整生命周期的bean对象。
        earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。早期是什么意思?表示Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。
        singletonFactories中缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的工厂。

解决循环依赖思路分析

        先来分析为什么缓存能解决循环依赖。
        上文分析得到,之所以产生循环依赖的问题,主要是:
                A创建时--->需要B---->B去创建--->需要A,从而产生了循环

那么如何打破这个循环,加个中间人(缓存)

 那么如何打破这个循环,加个中间人(缓存)


        A的Bean在创建过程中,在进行依赖注入之前,先把A的原始Bean放入缓存(提早暴露,只要放到缓存了,其他Bean需要时就可以从缓存中拿了),放入缓存后,再进行依赖注入,此时A的Bean依赖了B的Bean,如果B的Bean不存在,则需要创建B的Bean,而创建B的Bean的过程和A一样,也是先创建一个B的原始对象,然后把B的原始对象提早暴露出来放入缓存中,然后在对B的原始对象进行依赖注入A,此时能从缓存中拿到A的原始对象(虽然是A的原始对象,还不是最终的Bean),B的原始对象依赖注入完了之后,B的生命周期结束,那么A的生命周期也能结束。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【CSS】伪元素与伪类

CSS 伪元素和伪类 1.为什么要引入伪元素和伪类? 在 CSS 的官方文档中,是这样描述的: CSS introduces the concepts of pseudo-elements and pseudo-classes to permit formatting based on information that lies outside the document tre…

MAC在Linux上上传本地文件压缩包(tomcat)解决方法(炒鸡详细)

要将文件压缩包上传到Linux云服务器,并在服务器上解压打开,你可以使用以下步骤: 在本地的Mac上,将要上传的文件或文件夹压缩成一个压缩包(如zip或tar.gz格式)。 使用SSH连接到Linux云服务器。你可以使用Te…

模型剪枝Lab

这里是MIT 6.5940 Fall 2023的第一个实验Lab1的一些笔记,课程传送门:Han Lab Setup First, install the required packages and download the datasets and pretrained model. Here we use CIFAR10 dataset and VGG network which is the same as what…

【Spring Boot】035-Spring Boot 整合 MyBatis Plus

【Spring Boot】035-Spring Boot 整合 MyBatis Plus 【Spring Boot】010-Spring Boot整合Mybatis https://blog.csdn.net/qq_29689343/article/details/108621835 文章目录 【Spring Boot】035-Spring Boot 整合 MyBatis Plus一、MyBatis Plus 概述1、简介2、特性3、结构图4、相…

EXIT(1)

EXTI介绍 EXTI是片上外设 NVIC是cpu内的外设 回忆起之前的GPIO和AFIO 我们是如何检测按键按下的 我们是一直用while循环读取IDR寄存器的对应位置的值 一直检测判断按键是否被按下 那么是否有第二种方式检测按键是否被按下了呢? 通过EXTI 当EXTI检测到按键的电平发生…

C语言ZZULIOJ1149:组合三位数之二

题目描述 把1,2,3,4,5,6,7,8,9,组成三个三位数(每个数只能用一次),第二个数是第一个数的2倍,第三个数是第一个数的3倍,这三…

Hosts File Editor 实用工具

我一般手工编辑hosts文件,我想给hosts文件加一个开关,本想自己实现,但是忽然发现微软已经提供了官方的解决方案,感觉有能人。 对文件的行的修改被抽象成了一个开关。腻害!!!

使用百度语音识别技术实现文字转语音的Java应用

探讨如何使用百度语音识别技术将文字转换为语音的Java应用。百度语音识别技术是一种强大的语音识别服务,可以将输入的文字转换为自然流畅的语音输出。我们将使用Java编程语言来实现这个应用,并提供相应的源代码。 首先,我们需要准备一些前提…

Leetcode—67.二进制求和【简单】

2023每日刷题&#xff08;二十八&#xff09; Leetcode—67.二进制求和 实现代码 void reverse(char *a, int len) {for(int i 0; i < len / 2; i) {char tmp a[i];a[i] a[len - 1 - i];a[len - 1 - i] tmp;} }char* addBinary(char* a, char* b) {int len1 strlen(a…

计算机视觉:使用opencv实现银行卡号识别

1 概述 1.1 opencv介绍 OpenCV是Open Source Computer Vision Library&#xff08;开源计算机视觉库&#xff09;的简称&#xff0c;由Intel公司在1999年提出建立&#xff0c;现在由Willow Garage提供运行支持&#xff0c;它是一个高度开源发行的计算机视觉库&#xff0c;可以…

Django路由层解析

路由层(urls.py) Django的路由层是用于将URL映射到视图函数的机制。它用于确定请求URL&#xff08;HTTP请求&#xff09;应该被哪个视图函数处理。 Django的路由层包括两个部分&#xff1a; URL模式&#xff1a;匹配请求URL&#xff0c;决定应该使用哪个视图函数来处理请求。UR…

Windows配置wxWidgets开发

1、编译 从官网下载wxWidgets源码,解压后进入build/msw目录,按自己安装的VS版本去选择sln打开,在VS的菜单拦找到【生成】菜单下的【批生成】菜单,点击进入, 点选【全选】然后点【生成】按钮。等上两、三个小时在项目目录的lib文件夹就可以看到生成的dll与lib目录,如下: …

CountDownLatch使用

常用于多线程场景&#xff0c;待多线程都结束后方可继续主线程逻辑处理 CodeConstant 常量类 import java.util.HashMap; import java.util.Map;public class CodeConstant {public static final Map<String, Map<String, String>> CODE new HashMap<>();…

真心建议测试工程师学完Pytest框架实战,跳槽必备,学完能涨薪5k

【文章末尾给大家留下了大量的福利】 应用场景&#xff1a; pytest 框架可以解决我们多个测试脚本一起执行的问题。 它提供了测试用例的详细失败信息&#xff0c;使得开发者可以快速准确地改正问题。它兼容最新版本的 Python。它还兼容 unittest、doctest 和 nose&#xff0…

python双端队列_中间是头两边是尾_两边是头中间是尾

双端队列的顺序表存储结构以及两种特殊的双端队列 双端队列 是一种允许我们同时从前端和后端添加和删除元素的特殊队列&#xff0c;它是队列和栈的结合体。 双端队列&#xff08;deque&#xff09;与队列&#xff08;queue&#xff09;就差了两个字&#xff0c;队列里元素只能…

redis之org.springframework.data.redis.RedisSystemException: Error in execution

背景 在运行某系统时&#xff0c;在测试类向redis中存入某值&#xff0c;然后取出。 一、遇到的问题 报错&#xff1a; org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: …

基于Python实现,调用百度通用翻译API-详解

概述 在工作上需要各个国家语言的翻译方面很多地方用的上。 获取API权限: 登录百度账号,在个人信息界面,包括修改密码、绑定手机、身份人证等 https://api.fanyi.baidu.com/api/trans/product/desktop?req=developer 百度翻译开放平台 在开发者中心:需要开通个人账号…

我国陆地遥感卫星发展现状与展望

一、引言 从20世纪90年代末至今&#xff0c;我国陆地遥感卫星事业历经二十多年&#xff0c;实现了从无到有、从小到大、从弱到强的跨越发展。随着高分辨率对地观测系统重大专项&#xff08;高分专项&#xff09;、《陆海观测卫星业务发展规划&#xff08;2011—2020年&#xff…

通过Python设置及读取PDF属性,轻松管理PDF文档

PDF文档属性是嵌入在PDF文档中的一些与文档有关的信息&#xff0c;如作者、制作软件、标题、主题等。PDF属性分为默认属性和自定义属性两种&#xff0c;其中默认属性是一些固定的文档信息&#xff0c;部分信息自动生成&#xff08;如文件大小、页数、页面大小等信息&#xff09…

【ruoyi】微服务关闭登录验证码

登录本地的nacos服务&#xff0c;修改&#xff1a;配置管理-配置列表-ruoyi-gateway-dev.yml 将验证码的enabled设置成false&#xff0c;即可