Spring循环依赖

一、什么是循环依赖

        循环依赖指的是两个或多个bean之间通过构造函数或字段(setter方法)注入相互依赖,形成了一个闭环。举例:类A依赖类B,类B也依赖类A,这种情况就会出现循环依赖。 Bean A → Bean B → Bean A。如图1所示。

                                             图1

       循环依赖在设计和实现Spring应用程序时可能导致问题,因为Spring的默认依赖注入方式可能无法直接解决这种依赖关系。循环依赖还可能会导致内存溢出。

二、循环依赖的类型

在Spring中,循环依赖通常分为以下两种类型:

1.构造函数依赖注入(Constructor Injection):如果两个或多个bean通过构造函数相互注入,那么Spring无法处理这种循环依赖,因为它无法实例化一个bean,因为它依赖于另一个尚未实例化的bean,而这个bean又依赖于第一个bean。

2.Setter依赖注入(Setter Injection):通过setter方法注入依赖,Spring可以处理这种循环依赖。当使用setter注入时,Spring首先完全实例化每个bean,然后注入依赖项。因此,即使存在循环依赖,Spring也能通过后期设置依赖来解决。

三、Spring如何解决Setter注入的循环依赖

对于Setter注入的循环依赖,Spring使用了三级缓存(实际上是三个Map)来处理:

1.一级缓存(SingletonObjects):用于存储已经实例化、注入并初始化完成的bean。(所有成熟的bean)

2.二级缓存(EarlySingletonObjects):用于存储已经实例化但尚未完成依赖注入的bean(原生的早期bean)。

3.三级缓存(SingletonFactories):存储的是ObjectFactory,用于生成对应bean的早期引用(代理的bean)。

        当我们通过getBean()去获取一个对象实例时,Spring会先从一级缓存去找,没找到去二级缓存找,如果都没找到,意味着这个Bean还没有实例化,Spring容器会去实例化这个Bean,而这个初始化实例的Bean,叫做早期bean,然后会把这个目标Bean放入二级缓存,同时加入标记表示是否存在循环依赖,不存在的话放入二级缓存;存在循环依赖,等待下次轮询的时候复制(解析@Autowired),等@Autowired完成后,会将目标Bean存入一级缓存。如图2所示。

图2

        虽然Spring能够处理Setter注入的循环依赖,但构造函数注入的循环依赖则无法处理。因此,在设计应用程序时,应当尽量避免构造函数注入的循环依赖,或者重新考虑应用程序的架构和设计,以消除这种依赖。如果确实需要使用构造函数注入,并且存在循环依赖的情况,那么可能需要考虑使用其他设计模式或框架特性来解决这个问题。

四、关于三级缓存的一些问题

1.二级缓存能不能解决循环依赖?

a.如果只是死循环问题:一级缓存就可以解决

b.二级缓存也可以解决循环依赖:只不过如果出现重复循环依赖,会多次创建aop的动态代理。

2.Spring有没有解决多例的循环依赖?

  没有解决。

a.多例不会使用缓存进行存储(多例每次使用都需要重新创建)

b.不缓存早期对象就无法解决循环 

 3.Spring有没有解决构造函数参数Bean的循环依赖?

   没有,可以进行人工进行解决:@Lazy注解

a.不会立即创建循环依赖的bean了

b.等到用到才通过动态代理进行创建

4.三级缓存的顺序

        先从一级缓存中获取对象,如果没有再从二级缓存中获取,二级缓存中没有再从三级缓存中获取。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值