Spring三级缓存流程再梳理

本文主要是说下在使用spring时遇到了循环依赖,Spring利用三级缓存怎么解决

getBean(beanName)

doGetBean(name, null, null, false);
	getSingleton(beanName)方法, 最后会通过addSingleton(beanName, singletonObject)存到一级缓存里面去

createBean(beanName, mbd, args);

doCreateBean(beanName, mbdToUse, args);
	1、实例化普通对象,生成singletonFactory对象存到三级缓存里面去,任何对象都会存到三级缓存,因为后面存一级缓存的时候,都会把三级缓存里面删掉
	2、填充属性,包括循环依赖
	3、初始化处理,AOP代理对象,如果符合AOP逻辑,那么
	4getSingleton(false)从缓存中获取对象,为什么上面创建对象了,这里还要再次获取对象,主要是循环依赖的时候这里可能已经生成好了。

备注:singletonFactory.getObject和Bean的初始化都会经过AOP来判断一次是否需要创建代理对象,但是二者只会有一个创建代理对象,他们里面利用了一个中间earlyProxyReferences缓存,创建过就不会再创建了,这个缓存不是三级缓存别搞混了

案例1:A和B只是普通类之间的相互引用

1、A先创建普通实例,然后生成一个singletonFactory对象存到三级缓存,没有什么条件基本上都会被塞到三级缓存里面。
2、A属性填充,发现需要B

3、调用B的CreateBean,B创建普通实例,singletonFactory对象存到三级缓存,没有什么条件,都会存到三级缓存里面去。
4、B属性填充,B里面需要A,然后通过三级缓存里面找,发现有,通过getObject得到A的实例对象引用,在存到二级缓存里面去,注意这里是A的实例对象,和前面A创建的实例对象是同一个,为什么,因为getObject虽然会触发后置处理的调用,但是因为不走AOP所以,调用完后置处理器,返回的依旧是A的普通实例,而这个A的普通实例哪里来的,就是在生成singletonFactory对象时候,把一开始生成的普通对象穿进去的。
5、因为是普通实例,所以B执行后置处理器,不走AOP,返回的依旧是普通的实例
6、再把B从三级缓存中移除,存到一级缓存里面去。

7、再回到A,此时A调用getBean就可以返回B的实例对象,这个时候,B已经在1级缓存,A还在二级缓存里面。

8、A的属性填充完之后,调用初始化方法,走后置处理器,因为不是AOP所以初始化之后得到的A还是普通实例

9、在接着走getSingleton(false)方法,这个时候A已经被丢到了二级缓存,所以getSingleton也会拿到对象,但是这里拿到的对象和A一开始实例化的对象是一样的。

10、最后再把A塞到1级缓存,从二级缓存中移除。

案例2:A和B都会创建代理对象,2者相互引用。

首先需要知道,A和B都是先创建普通实例对象,然后在把A和B这个普通实例对象的属性填充好,在通过这个普通实例对象来生成代理对象,因为代理对象最终也是会拿到这个普通实例对象,调用目标具体方法。
并且,A和B的普通实例对象,里面的属性赋值,赋的是代理对象,不是普通实例对象。

1、先普通实例化A,然后生成一个singletonFactory对象存到三级缓存
2、属性填充,发现需要注入B

3、调用B的CreateBean,B创建普通实例,singletonFactory对象存到三级缓存

4、B属性填充,B里面需要引入A,调用getSingleton(A, true);因为A已经在三级缓存里面了,所以会触发A的singletonFactory.getObject方法

5、A这个时候就会通过SmartInstantiationAwareBeanPostProcessor后置处理器来创建A的代理对象,并且会把A从三级缓存中移除,A添加到二级缓存里面去。

6、B调用初始化方法,这个时候B会通过后置处理器来创建代理对象,具体哪个后置和选用注解有差异,比如@Aspect和@Async创建代理的后置处理器就不一样。此时B的实例已经变成了代理对象。

7、B在调用getSingleton(beanName, false);方法,返回Null因为穿了false,注意此时B还是三级缓存里面,A已经不在三级缓存里面了,A已经跑了二级缓存里面去了,并且A此时已经是一个代理对象了

8、最后返回B实例化好的代理对象,存到一级缓存里面,然后清空三级缓存。

9、回到A的属性填充逻辑,因为此时B已经实例化了,然后把A的属性赋好值。

10、开始触发A的初始化方法,通过后置处理器创建A的代理对象,当发现A已经在缓存earlyProxyReferences里面,说明已经创建过A的代理对象,所以就不在创建A的代理对象,此时初始化方法返回的还是A的普通实例对象。

11、A开始调用getSingleton(A, false);因为此时二级缓存已经保存了A的代理对象,将代理对象取出替换A的普通实例对象,返回A的代理对象。

12、最后将A的代理对象存到一级缓存里面去,在移除二级缓存里面的数据。

待确认:B这个类里面的属性,填充进去的是A的普通对象还是代理对象。 代理对象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值