彻底理解三级缓存和循环依赖(二)

又读了一遍源码现在对三级缓存有了新的理解,才发现网上很多写的三级缓存相关的东西都是错的,包括我自己之前的第一篇,也有理解不准确的地方,这里我简单描述一下正确的理解过程。
但是还是建议在阅读上一篇彻底理解三级缓存和循环依赖文章之后,再对此文进行阅读。

三级缓存

singletonObjects 保存了所有完整的bean对象。
earlySingletonObjects 保存了调用过三级缓存中getEarlyBeanReference()的,且还未完全创建的bean对象。
singletonFactories 他是一个工厂的保存,目的是过去已经实例化的bean对象,但是在获取过程中,会对这些bean对象进行一些处理,处理方式如下

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
			// 所有实现了SmartInstantiationAwareBeanPostProcessor接口的对象,调用其getEarlyBeanReference()方法。其实只有一个抽象类AbstratAutoProxyCreator实现了这个方法,也就是AOP操作。往earlyProxyReferences记录已经被AOP提前的bean对象,wrapIfNessary()方法去获取代理对象,是用CGlib还是用Proxy
				exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
		return exposedObject;
	}
	@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

所以总的来说,一级缓存用来保存完整的bean,二级缓存用来保存处理过AOP的bean,三级缓存用来获取bean,并实现AOP的提前。
为什么这么说,首先来看一下bean的创建过程,简化版如下。

初始化bean
放入三级缓存
依赖注入
各种aware操作
初始化和beanPostProcessor
放入一级缓存

依赖注入的过程是populate函数,然后调用selectCandidate()方法,通过beanName和类型去推断需要注入的bean,然后再去调用doGetBean方法。
然后getBean方法会去调用getSingleton()方法获取bean,这个方法如下。

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

简答来讲就是先从一级缓存中找,找不到再去二级缓存中找,找不到就去从三级缓存中找,如果是循环依赖,就能从在即缓存中找到这个工厂函数,并且调用,同时将这个bean放入二级缓存中,且从三级缓存中删除这个bean。然后拿到需要依赖的bean对象,可能是代理之后的bean对象,这里我们称其为被依赖bean,而依赖他的叫做原始bean。之后继续对原始bean做aware,beanPostProcessor和init操作,处理完后放入一级缓存。然后结束了,获取到这个bean。
这里主要讲一下为什么三级缓存用完之后要删除,然后放入二级缓存。
这个其实就关系到了二级缓存的主要作用,处理那些超过两个以上的循环依赖问题。例如A依赖B,B依赖A和C,C依赖A的情况,这个时候在beanB的创建过程中,首先从三级缓存中获取了A,并做了AOP提前,这时候C还没有创建,就要去创建C,而在C创建的过程中,又要去注入A,如果再用三级缓存区调用的话,就又会处理一次AOP导致报错,所以必须用一个缓存来记录那些已经AOP提前的,但是却还没有创建完成的,未放到一级缓存的。所以这里引入了一个二级缓存earlySingletonObjects.
其实命名的时候,确实也是下了工作,earlySingletonObjects,看名字也可以推断,是那些早期的,还未创建完全的bean对象的一个缓存。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Cofer_Yin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值