Spring如何处理循环引用
一,划重点
Spring处理循环依赖记录,要是写错了,喷轻一点。
解题核心:
1.AbstractBeanFactory的2个getSingleton方法
2.earlySingletonObjects Map
3.singletonFactories Map
4.singletonsCurrentlyInCreation Set
二,上图
看图说话:
场景:A对象持有B对象,B对象持有A对象。
三,解析
A引用B,B引用A。
获取A时:
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
然后第一次执行getSingleton()
Object sharedInstance = getSingleton(beanName);
@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;
}
第一次的时候肯定对是拿不到的,直接返回null。
第二次getSingleton()。
sharedInstance = getSingleton(beanName, () -> {
try {
// 创建Bean
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
AbstractBeanFactory.this.destroySingleton(beanName);
throw ex;
}
});
会执行getSingleton(),方法,并在执行到:
singletonObject = singletonFactory.getObject();
时,按照接口入参的函数式编程格式执行代码。也就是createBean()
此时仍是创建A。
相当牛逼的方法来了:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
这个方法会:
1.通过构造方法创建bean
2.将对象放入缓存处理循环依赖:singletonsCurrentlyInCreation 和singletonFactories
3.填充对象属性
doCreateBean会调用:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
// 后置处理器开始处理 注入属性
// CommonAnnotationBeanPostProcessor - 主要处理@Resource和初始化方法
// AutowiredAnnotationBeanPostProcessor - 大名鼎鼎的自动注入,处理 @Autowired
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
利用:
postProcessProperties的回调,填充Bean的属性。
如下是:AutowiredAnnotationBeanPostProcessor#postProcessProperties
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 找到需要注入的类型
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 反射调用 filed.set注入
// 在注入前,会获取注入类型的bean对象
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
此时调用到这里,bean还是A,但是pvs也就是要注入的属性,是B。
B会重新走一遍上面的流程,并且同样在此处,找到要注入的属性A。
当A在走上面流程时,在第一个getSingleton时,会获取到放入singletonFactories的A对象,然后返回。至此循环依赖处理完成。
findAutowiringMetadata这个方法可以看出Spring是怎么找属性的,但是我没看太明白。
inject(),可以讲一下:
这个inject()有点坑,要看清楚是那个inject()
AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 解决循环依赖上的路径之一
Field field = (Field) this.member;
Object value;
if (this.cached) {
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
} catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
} else {
// 牛皮glass
// 1.获取属性值 value = resolveFieldValue(field, bean, beanName);获取的是完整的属性值,举例:
// A持有B,则value为完整的B对象,且是放到了singletonObjects中的对象
// A持有B,B也持有A,循环引用,value也为B,且B中持有的A已经填充完毕,并且放入了singletonObjects中,但是A中的B还没填充。
// 经过下面代码 field.set(bean, value); A中的B就填充完成,至此循环依赖填充完毕
// 2.反射完成注入 field.set(bean, value);
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
接着调用到:
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
if (instanceCandidate instanceof Class) {
// 如果属性是一个类,就从beanFactory中取出来 - 非常重要
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(java.lang.String)
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
接着调用:
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
// 获取bean
return beanFactory.getBean(beanName);
}
这个getBean()是不是很熟悉,于是重复上面的流程。