在 spring 框架中,我们知道它是通过三级缓存来解决循环依赖的,那么它具体是怎么实现的,以及是否必须需要三级缓存才能解决循环依赖,本文来作相关介绍。
具体实现
先来看看它的三级缓存到底是什么,先看如下代码:
// DefaultSingletonBeanRegistry
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;
}
- 一级缓存: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 中进行。这样也体现了类的单一职责原则。