学习小记 -- Spring之三级缓存解决循环依赖

我们模拟A,B对象的循环依赖。

Bean的创建过程在

AbstractApplicationContext#refresh() -> finishBeanFactoryInitialization -> beanFactory.preInstantiateSingletons()的时候开始:

一次执行getBean() -> doGetBean() -> createBean() -> doCreateBean() 

在doGetBean()方法中,我们可以看到:调用了

this.singletonObjects.get(beanName)

会优先从一级缓存中查找。

 在A对象还未创建的时候,在一级缓存是拿不到Object的,所以doGetBean()方法回继续往下执行,一直到下图:

createBean()方法里传了一个lambda表达式,我们进去看看:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
       ...

        try {
			singletonObject = singletonFactory.getObject();
			newSingleton = true;
		}

       ...
}

 里面调用了getObject()方法

使用了@FunctionalInterface,说明是一个函数式接口,表明我们可以通过匿名内部类或者lambda表达式来调用getObject()方法来执行。

所以看似调用了 singletonFactory.getObject();方法,其实最终调用的是

createBean(beanName, mbd, args)方法,然后调用doCreateBean(),此时A对象已经是个半成品(只实例化,未初始化),里面有个
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
,看此方法:

先从一级缓存拿,如果拿不到,便将半成品A放到三级缓存singletonFactories中,k是beanName,v是传进去的lambda表达式

最终获取到A对象的半成品(只实例化,未初始化)。

继续开始填充属性

applyPropertyValues(beanName, mbd, bw, pvs);

里面当填充b属性的时候,发现此时的b属性类型是RuntimeBeanReferenc,进而执行处理逻辑,开始调用 this.beanFactory.getBean(refName); 由此又回到了对B对象的创建。

然后就是拿到了B对象的半成品,放入三级缓存。

接下来就是给B对象的a属性赋值,这里过程不详细讲解了,直接看一个重要的方法:

此时一二级缓存都为空,从三级缓存中拿,根据k,我们拿到了A对象所对应的lambda表达式

 () -> getEarlyBeanReference(beanName, mbd, bean);所以当调用getObject()方法是,实际上调用的是getEarlyBeanReference方法。 然后就得到了A的半成品对象,然后把半成品对象放入二级缓存,k:A , v:A的半成品对象;然后清空三级缓存中A对象 ,此时B对象就实例化结束了,然后把B对象放入一级缓存,k:b, v: B对象,清空三级缓存中B对象。

然后给A对象的b属性赋值,就可以从一级缓存中拿到B对象,赋值给b属性,A对象就完整了。最后把A对象放入一级缓存,清空二三级缓存中的A对象。

到此,A,B对象创建成功,循环依赖结束。

问:只用一级缓存可不可以?

答:不可以,一级缓存放成品,二级缓存放半成品,成品和半成品要分开,全用一级缓存会导致逻辑没法执行。

问:只用一二级缓存可不可以?

答:第三级缓存作用的本质是AOP代理问题,如果可以保证不调用getEarlyBeanReference方法,就可以不使用三级缓存。即,如果对象之间没有循环依赖,也不存在代理,就可以不使用三级缓存。

 问:为什么三级缓存可以解决AOP代理问题?

答:一个对象如果要被代理,在整个创建过程中必然包括此对象和代理对象,两者都是单例的且对象名相同,所以就要把两个对象分来存放,在使用的时候需要判断是否需要代理,如果需要则从三级缓存中拿代理对象。

ps: 

三个Map分别对应我们说的一级缓存,二级缓存,三级缓存。

总结:流程图如下:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值