spring循环依赖

在Spring中,循环依赖问题指的是两个或多个Bean之间相互依赖,形成了一个循环链。Spring提供了三种解决循环依赖问题的策略:

1. 构造器注入:通过构造器将Bean的依赖以参数的方式传递进去,而不是通过属性注入的方式。这种方式可以避免循环依赖的问题,但要求构造器的参数不能过多,不然会导致代码可读性差。

2. 属性注入:Spring通过使用代理来解决循环依赖问题。在创建Bean的过程中,如果出现循环依赖,Spring会创建一个代理对象,将该代理对象注入到依赖的Bean中,等到真正需要使用该Bean时,再通过代理对象来获取。

3. 使用@Lazy注解:通过使用@Lazy注解,可以延迟Bean的初始化,从而避免循环依赖问题。当使用@Lazy注解时,Spring会将Bean的初始化放到第一次使用时进行。

关于缓存的作用,Spring提供了多级缓存机制,主要有以下三级缓存:

缓存源码名称作用
一级缓存singletonObjects单例池; 缓存已经经历了完整声明周期, 已经初始化完成的bean对象
二级缓存earlySingletonObjects缓存早期的bean对象(生命周期还没有走完)
三级缓存singletonFactories缓存的是ObjectFactory, 表示对象工厂, 用来创建某个对象的

步骤如下所示:

1、实例化A得到A的原始对象

2、将A的原始对象存储到二级缓存(earlySingletonObjects)中

3、需要注入B,B对象在一级缓存中不存在,此时实例化B,得到原始对象B

4、将B的原始对象存储到二级缓存中

5、需要注入A,从二级缓存中获取A的原始对象

6、B对象创建成功

7、将B对象加入到一级缓存中

8、将B注入给A,A创建成功

9、将A对象添加到一级缓存中

三级缓存的作用:

从上面这个分析过程中可以得出,只需要一个缓存就能解决循环依赖了,那么为什么Spring中还需要singletonFactories ?

基于上面的场景想一个问题:如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象,此时就会出现,对于A而言,它的Bean对象其实应该是AOP之后的代理对象,而B的a属性对应的并不是AOP之后的代理对象,这就产生了冲突。 也就是说, 最终单例池中存放的A对象(代理对象)和B依赖的A对象不是同一个。

所以在该场景下, 上述提到的二级缓存就解决不了了。那这个时候Spring就利用了第三级缓存singletonFactories来解决这个问题。

singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories中,后期其他的Bean可以通过调用该ObjectFactory对象的getObject方法获取对应的Bean。

步骤如下所示:

1、实例化A,得到原始对象A,并且同时生成一个原始对象A对应的ObjectFactory对象

2、将ObjectFactory对象存储到三级缓存中

3、需要注入B,发现B对象在一级缓存和二级缓存都不存在,并且三级缓存中也不存在B对象所对应的ObjectFactory对象

4、实例化B,得到原始对象B,并且同时生成一个原始对象B对应的ObjectFactory对象,然后将该ObjectFactory对象也存储到三级缓存中

5、需要注入A,发现A对象在一级缓存和二级缓存都不存在,但是三级缓存中存在A对象所对应的ObjectFactory对象

6、通过A对象所对应的ObjectFactory对象创建A对象的代理对象

7、将A对象的代理对象存储到二级缓存中

8、将A对象的代理对象注入给B,B对象执行后面的生命周期阶段,最终B对象创建成功

9、将B对象存储到一级缓存中

10、将B对象注入给A,A对象执行后面的生命周期阶段,最终A对象创建成功,将二级缓存的A的代理对象存储到一级缓存中

注意:

1、后面的生命周期阶段会按照本身的逻辑进行AOP, 在进行AOP之前会判断是否已经进行了AOP,如果已经进行了AOP就不会进行AOP操作了。

2、singletonFactories : 缓存的是一个ObjectFactory,主要用来去生成原始对象进行了AOP之后得到的代理对象,在每个Bean的生成过程中,都会提前暴露一个工厂,这个工厂可能用到,也可能用不到,如果没有出现循环依赖依赖本bean,那么这个工厂无用,本bean按照自己的生命周期执行,执行完后直接把本bean放入singletonObjects中即可,如果出现了循环依赖依赖了本bean,则另外那个bean执行ObjectFactory提交得到一个AOP之后的代理对象(如果没有AOP,则直接得到一个原始对象)。

 只有一级缓存和三级缓存是否可行?

不行,每次从三级缓存中拿到ObjectFactory对象,执行getObject()方法又会产生新的代理对象,因为A是单例的,所有这里我们要借助二级缓存来解决这个问题,将执行了objectFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍objectFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象。

总结:所以如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行objectFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值