搜索
写经验 领红包

spig如何巧妙解决循环依赖问题为什么呢(spig循环依赖的解决办法)

导语:Spring如何巧妙解决循环依赖问题?为什么不是二级缓存?

读完本文,你会重温Spring生命周期,知道如何解决三级缓存问题,

知道为何需要三级缓存而不是二级缓存?

解答这个问题之前,我们先看一下Spring的bean的生命周期。

Spring bean生命周期:

1.实例化bean,分配内存地址

2.填充bean属性 ---- 循环依赖注入,利用三级缓存!!!

3.初始化bean

4.销毁bean

也就是说,填充bean属性的时候,包括循环依赖,也是在这一步解决的。

三级缓存

Spring利用 singletonObjects, earlySingletonObjects, singletonFactories三级缓存解决。

所说的缓存其实也就是三个Map

一级缓存singletonObjects :保存完整的bean实例,已经初始化/实例化好的bean.二级缓存earlySingletonObjects:保存被AOP代理/或没有代理 的半成品bean实例三级缓存singletonFactories:ObjectFactory半成品

我们直接看源码

首先在Bean实例化过程中,可以在源码中看到doCreateBean方法中:

实例化bean的步骤中,会调用addSingletonFactory方法,

提前把此bean暴露在三级缓存singletonFactories中 :

第一个参数是beanName,第二个参数是一个ObjectFactory匿名内部类实现。

假设现在有这样的场景AService依赖BService,BService依赖AService ;

1、AService首先实例化,由上面可知,实例化时,会把自己提前暴露在三级缓存中,key是自己的beanName,value是一个匿名内部类。

2、填充属性BService,发现BService还未进行过加载,就会先去加载BService

3、再加载BService的过程中,实例化,会把自己提前暴露在三级缓存中,key是,value是一个匿名内部类。

3.1、 此时需要,再填充属性AService的时候,这时候能够从三级缓存中拿到半成品的ObjectFactory

3.2、 拿到ObjectFactory对象后,调用ObjectFactory.getObject(), 此方法最终会调用匿名内部类的getEarlyBeanReference()方法

3.3、 getEarlyBeanReference方法,如果bean被AOP切面代理则返回的是beanProxy对象; 如果bean未被代理则返回的是原bean实例,这时我们会发现能够拿到bean实例,属性未填充的

3.4、 此时,就完成了BService实例化过程中,对其属性AService的填充了。

4、而此时B注入的是一个半成品的实例A对象,不过随着B初始化完成后,A会继续进行后续的初始化操作,最终B会注入的是一个完整的A实例;

重点:我们发现这个二级缓存好像显得有点多余,好像可以去掉,只需要一级和三级缓存也可以做到解决循环依赖的问题???

只要两个缓存确实可以做到解决循环依赖的问题,但是有一个前提这个bean没被AOP进行切面代理;如果这个bean被AOP进行了切面代理,那么只使用两个缓存是无法解决问题,下面来看一下bean被AOP进行了切面代理的场景因为AService是单例的,每次执行singleFactory.getObject()方法又会产生新的代理对象,假设这里只有一级和三级缓存的话,我每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象,这是不行的;因为AService是单例的,所有这里我们要借助二级缓存来解决这个问题,将执行了singleFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,避免再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象;

慢即是快~

本文内容由快快网络小娴创作整理编辑!