二级缓存中存的是半成品,用来解决对象创建过程中的循环依赖问题
三级缓存中存的是ObjectFactory<>类型的lambda表达式,用于处理存在AOP时的循环依赖问题
三级缓存的顺序是由查询循序而来,与在类中的定义顺序无关
所以第一级缓存:singletonObjects,第二级缓存:earlySingletonObjects,第三级缓存:singletonFactories
接口注入的方式太灵活,易用性比较差,所以并未广泛应用起来,大家知道有这么一说就好,不要去细扣了
构造方法注入的方式,将实例化与初始化并在一起完成,能够快速创建一个可直接使用的对象,但它没法处理循环依赖的问题,了解就好
setter方法注入的方式,是在对象实例化完成之后,再通过反射调用对象的setter方法完成属性的赋值,能够处理循环依赖的问题,是后文的基石,必须要熟悉
先创建的是Circle对象,那么我们就从创建它的populateBean开始,再开始之前,我们先看看三级缓存中的数据情况
此时三级缓存中的数据没有变化,但是Set
loop实例化完成之后,对其属性circle进行填充,去Spring中获取circle对象,又来到了熟悉的doGetBean
此时一、二级缓存(singletonObjects``earlySingletonObjects)中都没有circle、loop,而三级缓存中有这两个
通过getSingleton获取circle时,三级缓存调用了getEarlyBeanReference,但由于没有AOP,所以getEarlyBeanReference直接返回了普通的半成品circle
然后将半成品circle放到了二级缓存,并将其返回,然后填充到了loop对象中
此时的loop对象就是一个成品对象了;接着将loop对象返回,填充到circle对象中,如下如所示
我们发现直接将成品loop放到了一级缓存中,二级缓存自始至终都没有过loop,三级缓存虽说存了loop,但没用到就直接remove了
此时缓存中的数据,相信大家都能想到了
比上一种情况多了AOP,我们来看看对象的创建过程有什么不一样;同样是先创建Circle,在创建Loop
创建过程与上一种情况大体一样,只是有小部分区别,跟源码的时候我会在这些区别上有所停顿,其他的会跳过,大家要仔细看
实例化Circle,然后填充半成品circle的属性loop,去Spring容器中获取loop对象,发现没有
则实例化Loop,接着填充半成品loop的属性circle,去Spring容器中获取circle对象
这个过程与前一种情况是一致的,就直接跳过了,此时三级缓存中的数据如下:
将半成品circle的代理对象放到了第二级缓存中,并将代理对象返回赋值给了半成品loop的circle属性
注意:此时是在进行loop的初始化,但却把半成品circle的代理对象提前创建出来了
loop的初始化还未完成,我们接着往下看,又是一个重点,仔细看
在initializeBean方法中完成了半成品loop的初始化,并在最后创建了loop成品的代理对象
loop代理对象创建完成之后会将其放入到第一级缓存中(移除第三级缓存中的loop,第二级缓存自始至终都没有loop)
然后将loop代理对象返回并赋值给半成品circle的属性loop,接着进行半成品circle的initializeBean
因为circle的代理对象已经生成过了(在第二级缓存中),所以不用再生成代理对象了;将第二级缓存中的circle代理对象移到第一级缓存中,并返回该代理对象
此时各级缓存中的数据情况如下(普通circle、loop对象在各自代理对象的target中)
Map
第三级缓存提前创建circle代理对象,不提前创建则只能给loop对象的属性circle赋值成半成品circle,那么loop对象中的circle对象就无AOP增强功能了
第二级缓存用于存放circle代理,用于解决循环依赖;也许在这个示例体现的不够明显,因为依赖比较简单,依赖稍复杂一些,就能感受到了第一级缓存存放的是对外暴露的对象,可能是代理对象,也可能是普通对象
所以此种情况下:三级缓存一个都不能少
循环依赖+AOP这种情况中,circle代理对象的生成提前了,因为必须要保证其AOP功能,但loop代理对象的生成还是遵循的Spring的原则
如果我们打破这个原则,将代理对象的创建逻辑提前,那是不是就可以不用三级缓存了,而只用两级缓存了呢?
去除了第三级缓存,并将代理对象的创建逻辑提前,置于实例化之后,初始化之前;
1、三级缓存各自的作用
第一级缓存存的是对外暴露的对象,也就是我们应用需要用到的
第二级缓存的作用是为了处理循环依赖的对象创建问题,里面存的是半成品对象或半成品对象的代理对象
第三级缓存的作用处理存在AOP+循环依赖的对象创建问题,能将代理对象提前创建
2、Spring为什么要引入第三级缓存
严格来讲,第三级缓存并非缺它不可,因为可以提前创建代理对象
提前创建代理对象只是会节省那么一丢丢内存空间,并不会带来性能上的提升,但是会破环Spring的设计原则
Spring的设计原则是尽可能保证普通对象创建完成之后,再生成其AOP代理(尽可能延迟代理对象的生成)
所以Spring用了第三级缓存,既维持了设计原则,又处理了循环依赖;牺牲那么一丢丢内存空间是愿意接受的