首页 > 其他分享 >5.循环依赖

5.循环依赖

时间:2023-09-25 12:02:25浏览次数:38  
标签:依赖 创建 CircleA CircleB Bean 循环 Spring


循环依赖就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环。此处不是循环调用,循环调用是方法之间的环调用。循环调用是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出错误。

Spring如何解决循环依赖

Spring容器循环依赖包括构造器循环依赖和setter循环依赖

一、构造器参数循环依赖:通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出

BeanCurrentlyInCreationException异常表示循环依赖。

如在创建CircleA类时,构造器需要CircleB类,那将去创建CircleB,在创建CircleB类时又发现需要CircleC类,则又去创建CircleC,然后在创建CircleC时发现又需要CircleA;从而形成一个环,没办法创建。

Spring容器将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出

BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。

配置文件如下:

<bean id="circleA" class="com.spring.depend.bean.CircleA">
    <constructor-arg index="0" ref="circleB"/>
</bean>
<bean id="circleB" class="com.spring.depend.bean.CircleB">
    <constructor-arg index="0" ref="circleC"/>
</bean>
<bean id="circleC" class="com.spring.depend.bean.CircleC">
    <constructor-arg index="0" ref="circleA"/>
</bean>

测试一下:

public static void main(String[] args) {
    new ClassPathXmlApplicationContext("depend/circleInjectByConstructor.xml");
}

报错如下:

5.循环依赖_Java

正如前面所说,Spring容器先创建单例CircleA,CircleA依赖CircleB,然后将CircleA放在“当前创建Bean池”中,此时创建CircleB,CircleB依赖CircleC,然后将CircleB放在“当前创建Bean池”中,此时创建CircleC,CircleC又依赖CircleA, 但是,此时CircleA已经在池中,所以会报错,因为在池中的Bean都是未初始化完的,所以会依赖错误 ,(初始化完的Bean会从池中移除)

 

二、setter方式单例,默认方式,使用一个单例工厂方法,从而使其他Bean能引用到该Bean,先看一张Spring中Bean实例化的图

5.循环依赖_spring_02

 

配置文件如下:

<bean id="circleA" class="com.spring.depend.bean.CircleA">
     <property name="circleB" ref="circleB"/>
</bean>
<bean id="circleB" class="com.spring.depend.bean.CircleB">
    <property name="circleC" ref="circleC"/>
</bean>
<bean id="circleC" class="com.spring.depend.bean.CircleC">
    <property name="circleA" ref="circleA"/>
</bean>

下面是测试类:

public static void main(String[] args) {
    new ClassPathXmlApplicationContext("depend/circleInjectBySetterAndSingleton.xml");
}

再次运行却没有报错,结合上图分析,Spring先是用构造实例化Bean对象 ,此时Spring会将这个实例化结束的对象放到一个Map中,并且Spring提供了获取这个未设置属性的实例化对象引用的方法。结合我们的实例来看,当Spring实例化了circleA、circleB、circleC后,紧接着会去设置对象的属性,此时circleA依赖circleB,就会去Map中取出存在里面的单例circleB对象,以此类推,不会出现循环的问题。

三、setter方式原型,prototype

修改配置文件如下:

<bean id="circleA" class="com.spring.depend.bean.CircleA" scope="prototype">
     <property name="circleB" ref="circleB"/>
</bean>
<bean id="circleB" class="com.spring.depend.bean.CircleB" scope="prototype">
    <property name="circleC" ref="circleC"/>
</bean>
<bean id="circleC" class="com.spring.depend.bean.CircleC" scope="prototype">
    <property name="circleA" ref="circleA"/>
</bean>

scope="prototype" 意思是每次请求都会创建一个实例对象。两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。

测试类:

public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("depend/circleInjectBySetterAndPrototype.xml");
        System.out.println(ctx.getBean("circleA"));
    }

运行发现原型模式也会报错,因为对于”作用域为“prototype”的Bean,Spring容器无法完成依赖注入,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。

 



 

标签:依赖,创建,CircleA,CircleB,Bean,循环,Spring
From: https://blog.51cto.com/u_6947107/7594397

相关文章

  • python基础 循环嵌套
    嵌套语句使用星号打印foriinrange(1,6):forxinrange(1,i+1):print('*',end='')print('')foriinrange(1,6):forxinrange(i,6):print('*',end='')print('')99乘法表  while......
  • golang 的循环导入
    内容来自对chatgpt的咨询循环导入概念在Go语言中,循环导入是一个需要避免的问题。它发生在两个或更多的包彼此导入对方,形成一个导入循环,导致编译器无法处理。例如,假设你有两个包,包A和包B。包A导入了包B,然后包B又导入了包A,这就形成了一个循环导入。在这种情况下,编译器将无法......
  • 【算法】循环不变式
    循环不变式一、数学归纳法因为循环不变式的定义与数学归纳法类似,所以我们先来看看数学归纳法。我们首先从高中开始回忆起,有关于数列的数学归纳法。一般的,证明一个与正整数\(n\)有关的命题,可以分为以下两个步骤[1]:1.归纳奠基:证明当\(n=n_0(n_0\inN^*)\)时,命题成立。2......
  • labview中for循环用法
    说明:记录一下自己用到的和知道的for用法。 1、基本概念for循环位置:程序面板-编程-结构-for循环for的作用:可以使for循环体内的代码执行一定的次数。这文本语言类似。for重要参数:N表示循环总数,可输入可输出,都表示循环总数。            i表示当前循......
  • python基础 while,for循环
    whlie循环格式while结束条件:执行语句break结束if条件:break小游戏案例猜拳小游戏importrandomren=0ji=0print('-'*12+'欢迎玩猜拳小游戏'+'-'*12)print('本游戏实行三拳两胜制')n=0whilen<3:ran=random.randint(0,2)guess......
  • Lua08——Lua循环
    有时需要进行规律性的重复操作,需要用到程序中的循环语句。循环语句是由循环体及循环的终止条件两部分组成。循环语句是在一定条件下反复执行一段程序的流程结构,被反复执行的程序称为循环体。循环是否结束,取决于循环的终止条件。1Lua中的循环方式循环类型描述while在条件为true时......
  • 11-JavaScript 逻辑条件 ,if判断 ,while循环,算数运算相关的案例演示
    1、案例:猜数字设置一个1-10之间的随机数,然后输入进行猜数字,猜的大了怎么样、猜的小了怎么样、猜对了怎么样知识点:设置随机数、if判断、while循环写题思路:1.设置弹框提出问题2.定义一个随机数0-10的数组3.if判断取值的范围,在其范围内反馈的结果4.while循环,直到猜对停止......
  • python 循环 import模块
    关于循环while条件:当条件为true时,不断执行子代码foriinrange(20):循环20次子代码break结束当前循环continue跳过当前循环importrandom模块random.choice()随机一个参数random.sample(数据源,3)从数据源中随机抽3个值random.randint(1,100)打印一个随机数......
  • 【Spring使用三级缓存解决循环依赖的过程】
    testService1和testService2相互依赖当Spring创建testService1对象时,它会先从一级缓存中查找是否存在testService1的实例。如果缓存中不存在testService1实例,它将继续查找二级缓存中是否存在testService1。如果二级缓存中也不存在testService1实例,则Spring会尝试从三级缓存中获取......
  • 解决本地maven仓库有jar包却还要读取私服依赖的问题
    请打开你自己的本地仓库,对应依赖路径下的_remote.repositories文件。如果是从远程仓库拉取的,这里一般是显示这个:junit-4.12.jar>alimaven=junit-4.12.pom>alimaven=这个说明是从阿里云远程仓库拉取的代码由于这里的配置,使得你每次下载,他都会优先从阿里云远程仓库拉代码,而不是优先......