在 spring 框架中,我们知道它是通过三级缓存来解决循环依赖的,那么它具体是怎么实现的,以及是否必须需要三级缓存才能解决循环依赖,本文来作相关介绍。
具体实现
先来看看它的三级缓存到底是什么,先看如下代码:
// DefaultSingletonBeanRegistry
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject 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 locksingletonObject = 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;
}
- 一级缓存:singletonObjects
- 二级缓存:earlySingletonObjects
- 三级缓存:singletonFactories
获取实例对象的时候,先去一二级缓存查找,如果没找到,allowEarlyReference 为 true,会对 singletonObjects 加锁,并进行二次查找,还是找不到,会通过三级缓存,获取一个 singletonFactory,通过 singletonFactory 获取实例对象。
下面来看看这个 singletonFactory 是什么?
在 AbstractAutowireCapableBeanFactory#doCreateBean 中有这么一段代码:
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
}
放入了一个 lambda 表达式,即在实例化完一个实例对象之后,将这个半成品通过 singletonFactory 提前暴露出去,接着再进行 populateBean、applyPropertyValues 调用。
实例对象创建过程
下面来看看实例对象创建时的具体过程 ,如上图所示,A 引用 B,B 引用 A。
实例化完 A 之后,将 A 提前暴露,接着进行属性填充,此时发现需要 B,而 B 还未创建,接着去创建 B,实例化完 B 之后,也将 B 暴露出去,接着进行属性填充,此时需要 A,接着去找 A,由于 A 已经提前暴露了,会获取到 singletonFactory,接着调入 getEarlyBeanReference。
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);}}return exposedObject;
}
存在 SmartInstantiationAwareBeanPostProcessor 接口子类时,调用对应实现的 getEarlyBeanReference,主要是 AOP 增强时使用。
// AbstractAutoProxyCreator
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);
}
将实例化后的半成品放入 earlyProxyReferences,接着对其进行包装,即 AOP增强。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE); // 需要拦截,标记Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE); // 不需要拦截,标记return bean;
}
如果 A 中的方法需要增强,getAdvicesAndAdvisorForBean 方法会遍历注册的 beanDefinitionNames,找到匹配的 advisorNames,接着遍历 advisorsNames,创建对应的 advisor,填充属性需要 advice,进行 advice 的创建,最终完成 advisor 的创建,此时创建的 advisor 只是候选,具体能否为当前 A 使用,还需进行匹配判断,最后将匹配的 advisor 返回,即 specificInterceptors,接着对 A 进行标记,创建 proxy 返回。
返回的 proxy 会放入二级缓存 earlySingletonObjects,并将三级缓存中的 singletonFactory 删除。
拿到对这个半成品创建的 proxy,完成 B 的属性填充,接着进行 B 的初始化,如果 B 也需要 AOP 增强,执行 AbstractAutoProxyCreator#postProcessAfterInitialization。
// AbstractAutoProxyCreator
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
最后返回的就是增强后的 B,接着将 B 填充进 A,完成 A 的属性填充。进行 A 的初始化,此时调用 postProcessAfterInitialization 传入的参数 bean 还是一开始实例化的 bean,并不是创建 B 时增强的 proxyA,从 earlyProxyReferences 移除后与传入的参数 bean 相等,不会进行二次增强。
现在有一个问题,出现了两个 A,一个是普通的 A,一个是增强后的 proxyA,接着看看 spring 中的处理。
if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}}
}
通过 getSingleton 再获取一次,此时会从二级缓存获取到增强后的 proxyA,接着判断成立,会将proxyA 作为 exposedObject 返回,并将其注册到一级缓存 singletonObjects。
现在,我们可以知道每个缓存里存放的具体是什么了:
- 一级缓存 singletonObjects:完全的单例对象
- 二级缓存 earlySingletonObjects:半成品的 AOP 的增强对象
- 三级缓存 singletonFactories:获取半成品对象 或着 生成半成品 AOP 增强的工厂方法
由此可知,解决循环依赖,并不是必须需要三级缓存,如果没有 AOP 增强,只采用 singletonObjects 和 singletonFactories 两级缓存就可以解决循环依赖。而二级缓存 earlySingletonObjects,专为解决 AOP 而存在。
并且,对于A,返回 proxyA,对于 B,填充的就是 proxyA,而 proxyA 又是 A 子类,这样 proxyA 也就拥有了 A 中填充的属性。即 proxyA 只是对方法进行增强,而属性填充还是在 A 中进行。这样也体现了类的单一职责原则。