singletonFactories(三级缓存):存放创建bean的factory实例
earlySingletonObjects(二级缓存):存放还未填值的bean对象
singletonObjects(一级缓存):存放最终生成的bean实例
所谓循环依赖,简单的说:定义Bean A内部引用了Bean B,同时定义Bean B内部引用了Bean A。
解决循环依赖问题
初始化对象属性有2种方式:1. 通过有参构造。 2. 通过get() set()方法赋值。
如果是通过有参构造创建对象,无法解决循环依赖问题,你会发现创建语句像俄罗斯套娃一样无休无止。
所以只有先new空对象,在通过set的方式赋值。
注意这里讨论的是默认的单例模式的bean。prototype模式的bean无法解决循环依赖问题。
Spring的三级缓存
在Spring内部,创建一个singleton的bean要经历三级缓存的存放,从三级到一级,由bean工厂变为初始化还未填值的bean最终到完整的bean,就好像龙珠里沙鲁进化的过程。缓存不是永久存放的,到了下一个阶段,当前阶段的缓存就要被删除。
Spring是通过三级缓存来解决创建bean过程中的循环依赖问题的。
再看A-B循环引用的创建过程:首先创建A,依次从一级到三级缓存里查找A的实例,没有则在三级缓存里面生成了A(此时A是一个lamda表达式),然后填充A属性的过程中发现内部引用了B,于是进入创建B的流程,从一级到三级缓存查找发现B也没有,于是在三级缓存里创建了B (lamda表达式),填充B属性的时候发现内部引用了A,于是再从一级到三级缓存查找,发现三级缓存中有A,并且A可以转到earlySingletonObjects(内部控制逻辑),于是把A移动到二级缓存,同时清除三级缓存中的A,之后A中发现依赖了B,并且发现B也在创建过程中(类似一个变量控制),于是在一级缓存中创建了B(bean对象),同时清理三级缓存中的B,然后再填充,发现A,最终A也被转移到了一级缓存。
这个过程看起来很复杂,可以理解为两脚登台阶,首先左右脚依次站上底层台阶,然后先迈左脚上一层,然后再迈另一只脚踩上更高一层,总共就三层台阶,最终两只脚都站上第三层台阶。
通过设计这个规则让2个互相引用对象在不同级缓存的转移过程中完成自我创建和填充属性。
网友评论