Spring循环依赖

在Spring中,对象的创建 分为两个部分,一个是实例化,另一个是初始化,两个对象A、B互相引用,在对象初始化过程中会有如下的步骤:

1
2
3
4
5
6
7
public class A {
private B b;
}

public class B {
private A a;
}

上图中,会形成一个闭环,怎么解决这个问题呢?

如果想解决这个问题,那么久必须要保证不会出现第二次创建A对象这个步骤,也就是说从容器中获取A的时候必须要能够获取到这个对象

在spring中,对象的创建可以分为实例化和初始化,实例化好但未完成初始化的对象可以直接给其他对象引用的,所以此时可以做一件事情,把完成实例化但未完成初始化的对象提前暴露出去,让其他对象能够进行引用,就完成了这个闭环的解环操作————这就是常说的提前暴露对象(一二三级缓存)

Spring 三级缓存分布存放不同阶段的对象

一级缓存:Map< beanName,成品对象 >

二级缓存:Map<beanName,半成品对象 >

三级缓存:Map< beanName,lambda表达式 >

spring源码中,有一个方法 getSingleton() ,这个方法里面,获取bean的时候,会依次从一级、二级、三级缓存中获取对象

循环依赖相互引用类对象的过程分析:

有对象 A{ b = new B }和对象B{ a = new A } 相互引用

如果发生循环依赖的对象,不需要代理的话,只需要二级缓存足以解决所有问题,但是当存在代理之后就无法解决了,必须使用三级缓存来解决(或者别的方法来解决,spring中使用的是三级缓存的方式)

没有动态代理的时候,可以在源码中将加三级缓存的地方,直接添加到二级缓存中,getBean的时候直接从二级缓存中获取即可,这样就可以对源码进行对应的改动,但是如果有代理的情况下,就不能这么改动了

如果有动态代理的情况上面这种改动就会出问题

为什么?

如果按照上面的方式改动,将对象添加到容器的时候就会创建代理对象(自己会添加到容器中,可能会通过代理的方式添加)

在整个容器的生命周期中,可能会存在几个相同beanName的Bean对象

这样在getBean 的时候就会获取到多个,所以会报错

怎么解决这个问题?

三级缓存

在获取具体对象的时候,直接生成对应的代理对象,在获取的时候通过lambda表达式动态生成。

三级缓存中只能存在一个A的普通对象或者A的代理对象,不能同时存在


Spring循环依赖
http://yoursite.com/post/a5d86a59.html/
Author
Chase Wang
Posted on
November 7, 2021
Licensed under