Spring如何解决循环依赖的

目录

Spring使用三级缓存解决循环依赖

一级缓存能解决循环依赖问题吗?

二级缓存SingletonObject和SingletonFactory可以解决循环依赖吗?

二级缓存SingletonObject和EarlySingletonObject可以解决循环依赖吗?


Spring使用三级缓存解决循环依赖

三级缓存:

  • SingletonObject:全成品(10):key:beanName value:实例化并初始化完成的对象
  • EarlySingletonObject:半成品(5):key:beanName value:实例化好的对象(如果需要aop代理,则此时已被Aop代理)
  • SingletonFactory:半半成品(3):key:beanName value:ObjectFactory

一个对象进入缓存的顺序:

  • 初始都是进入到三级缓存,一旦有人引用它将他提为二级缓存,创建完毕之后进入一级缓存,
  • 每个对象只存在于一个缓存中, 没人引用它最后它初始化完毕后也会从三级缓存直接进入一级缓存

解决循环依赖的过程总结:

  1. A实例化后放入三级缓存,发现依赖B又去初始化B
  2. B实例化后放入三级缓存,发现依赖A又去初始化A,此时发现A在三级缓存中,将A提到二级缓存后依赖进去,然后初始化B最后将B放入一级缓存
  3. 然后A将B的依赖解决后,继续创建直到完毕

更加详细的源码过程如下:

spring循环依赖解决原理:循环依赖:A->B B->A

创建A:

  • 依次从一级缓存,二级缓存,三级缓存获取看有没有,一旦获取到直接返回
  • 发现没有所以创建:
  • 首先实例化new,然后直接放入三级缓存:beanName:a,value:a对应的ObjectFactory(这是以防循环依赖的,此时是半半成品,所以放入最原始的缓存)
  • populate执行autowired
  • 初始化(beforeInit init afterInit)
  • 放入ioc容器(放入一级缓存,并从二三级缓存移除)

创建B:

  • A的populate执行autowired会去创建B

创建B的过程:

  • 依次从一级缓存,二级缓存,三级缓存获取看有没有,一旦获取到直接返回
  • 发现没有所以创建:
  • 首先实例化new,然后直接放入三级缓存:beanName:b,value:b对应的ObjectFactory(这是以防循环依赖的,此时是半半成品,所以放入最原始的缓存)
  • populate执行autowired
  • 初始化(beforeInit init afterInit)
  • 放入ioc容器(放入一级缓存,并从二三级缓存移除)

创建B:

  • B的populate执行autowired会去创建A
  • 创建A:
  • 依次从一级缓存,二级缓存,三级缓存获取看有没有,此时发现最后面的三级缓存有A,
  • 所以将A从三级缓存获取出来调用其getObject获得(此方法里也处理了aop), 并将其移动到二级缓存,成了5成品,别人如果再来获取可以直接使用这个5成品,没必要再使用3成品了,
  • 接着B执行完populate后继续创建完毕(B创建完毕后此时B在一级缓存,A被B提到了二级缓存)
  • 创建B完成后:然后程序返回到A的populate之后继续创建A(此时A也被一入了一级缓存,A和B都在一级缓存)

一级缓存能解决循环依赖问题吗?

不能

因为全成品和半成品放到一起的话,半成品有可能被提前获取走,这时候还没有被赋值,所以会有问题。

二级缓存SingletonObject和SingletonFactory可以解决循环依赖吗?

不可以

在某个对象创建完成之前都必须一直放在SingletonFactory,其他bean使用这个半成品的时候都需要去SingletonFactory获取并执行其getObject方法。但是这个getObject其实只能执行一次,如果有多个bean的生成调用其getObject那么每个人拿到的代理都是不同的,就不是单例了。

二级缓存SingletonObject和EarlySingletonObject可以解决循环依赖吗?

可以 但是不好

这样的话,我们在向EarlySingletonObject里面放对象的时候就得首先判断是否需要提前Aop代理然后放进去。不需要还好,如果需要的话,生成代理放进去,但是最后没有人来引用,不是白生成了吗,如果白生成很多,那就很不好了因为后面AOP代理并没有用到这个提前的Aop代理,一般的代理是在initlize的AfterInit后置处理器中

猜测:

spring应该是先用到一级缓存和三级缓存 然后发现三级缓存的getObject只能调用一次

此时调用一次后因为是半成品又不能放入一级缓存 所以才想到二级缓存

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值