文章目录
1.引言
之前在从源码分析spring如何解决循环依赖一文中大概说明了spring是如何解决循环依赖的,侧重于从源码层面讲spring如何解决循环依赖,今天将对之前的文章进行内容补充,说明以下问题
- 构造函数注入在什么情况下支持循环依赖
- spring为什么使用了3级缓存而不是2级缓存
2.相关问题说明
2.1构造函数注入在什么情况下支持循环依赖?
首先,假设A、B两个bean互相依赖;A先实例化,B后实例化;
- 如果全是构造函数注入,在A实例化前,需要先实例化B,而实例化B的时候,又需要实例化A,A实例化又需要实例化B……陷入无限的死循环;因此,全是构造函数注入不支持循环依赖。
- 如果A是构造函数注入,B是setter注入;在实例化A前,需要实例化B,实例化B前又需要实例化A……还是陷入无限的死循环;因此,第一个实例化的bean是构造函数注入也不支持循环依赖。
- 如果A是setter注入,B是构造函数注入;A可以先实例化,因为是setter注入,后面可以再注入;B实例化的时候,需要从构造函数传入A,而A已经实例化,所以B也可以实例化;最后实例化后的B被setter注入到A中;因此,后实例化的Bean是构造函数注入支持循环依赖。
2.2 spring为什么使用了三级缓存而不是二级缓存?
2.2.1 二级缓存能否解决循环依赖?
其实单纯解决循环依赖,2级缓存足矣,
-
我们先看看一级缓存能不能够解决循环依赖;
假设有一级缓存 fCache,以上面第三种情况的Bean A、B为例;A实例化完成还未进行依赖注入先放到fCache中;这时创建B,从fCache取出A构造注入给B,B创建完成,放到fCache中;但这时A还未进行依赖注入,循环依赖没能解决; -
如果是加一级缓存作为二级缓存sCache,把创建完成的bean放到一级缓存fCache,把未创建完成但实例化的bean放到二级缓存sCache;所有的bean全放到一级缓存fCache才算创建完成;还是以第三种情况的Bean A、B为例;
A实例化后,先放到二级缓存sCache,再进行setter注入,这时发现需要B;
B实例化,从二级缓存中拿到了A进行构造注入,B创建完成,放入了一级缓存;
再回到为A依赖注入的过程中,从一级缓存fCache拿到B,为Asetter注入,A创建完成放入一级缓存fCache;
循环依赖完美解决。因此,单纯解决循环依赖,二级缓存足矣。
2.2.2 spring为什么使用了3级缓存?
众所周知,spring的两大特性,一大是IOC,另一大便是AOP了,spring提供了两个接口来实现AOP
- BeanFactoryPostProcessor
- BeanPostProcessor