Spring源码分析——循环依赖
Spring源码分析——循环依赖
在spring中,涉及到一个概念,叫做循环依赖,或者叫做循环引用。意思就是说,一个bean他的属性,依赖了另外一个bean,而他所依赖的bean,有恰好依赖与他。这种情况下,spring对此做了特殊处理,但是仅限于单例模式。
具体流程
处理循环依赖的具体流程,首先是在一个bean实例化后初始化前,如果判断判断符合循环依赖的条件,则提前把他暴露出去,但是不是暴露这个bean,而是封装成一个ObjectFactory对象,存放到二级缓存singletonFactories中,他的类型是Map<String,ObjectFactory<?>>。接下来在属性注入的端,发现他依赖了另外一个bean,那么又会去getBean进行bean的创建和初始化,然后同样也在实例后初始化前把他封装为ObjectFactory对象,放入二级缓存,然后就进行属性注入。而他又回过头来依赖了原来的bean,所有又调用了getBean获取原来的bean,这是后getBean一进来,从二级缓存中取到了,就不会往下进行这个bean的实例化了,然后完成了先把他赋值个第二个bean的成员变量,然后原来的bean也完成属性注入和初始化回调。
具体步骤:
- A依赖了B,B又依赖A
- getBean(A),创建A
- 判断符合循环依赖条件,把A的ObjectFactory对象放入二级缓存,这个对象的getObject方法,会返回A
- 进行属性注入
- 发现依赖了B,getBean(B),进行B的创建
- B也走了上面1-5步
- B 依赖了 A,所以A又调用 getBean(A)
- 这是二级缓存中已经存了A的ObjectFactory,就调用ObjectFactory的getObject方法,返回A,不再继续往下进行实例化
- B 先完成属性注入和初始化回调
- A 也完成属性注入和初始化回调
尝试从缓存中获取的具体流程
在调用getBean方法创建或后取一个bean是,首先会去缓存中取,如果从三个缓存池的随便一个当中取到了,就不会往下进行实例化。
getBean或走到doGetBean方法,然后里面有一行代码,是关于从缓存中尝试获取bean的逻辑
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
/**
* 尝试从BeanFactory的三个缓存池中获取该bean
* 获取得到则返回,不走下面的创建初始化方法。
* 此处作用:
* 1.给已经创建过的bean,再调getBean是获取该bean
* 2.处理循环依赖时返回该bean的半成品(已创建未初始化)
*/
Object sharedInstance = getSingleton(beanName);
已经完成初始化的bean,以及循环依赖时提前暴露的bean,在这里都可以获取到,不管是哪一种,只要获取到了,就不会往下进行重复的实例化工作。
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
@Override
@Nullable
public Object getSingleton(String beanName) {
/* allowEarlyReference为true表示允许循环引用 */
return getSingleton(beanName, true);
}
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
/*如果从一级缓存取到则直接返回,一般出现在获取已经完成的bean,或者单向引用 */
Object singletonObject = this.singletonObjects.get(beanName);
/*获取不到且当前beanName对应的Bean正在创建中(实例化后初始化前)*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
/*先从三级缓存中取*/
singletonObject = this.earlySingletonObjects.get(beanName);
/*三级完成取不到 && 允许循环引用*/
if (singletonObject == null && allowEarlyReference) {
/*从二级缓存中获取当前Bean对应的ObjectFactory */
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
/*获取到了,则调用getObject,获取当前正在创建中的对象*/
singletonObject = singletonFactory.getObject();
/*添加到三级缓存*/
this.earlySingletonObjects.put(beanName, singletonObject);
/*从二级缓存中删除,下次就直接从二级缓存中取了*/
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这里可以看到spring的三个缓存次,singletonObjects-一级缓存池,也就是俗称的单例缓存池,singletonFactories-二级缓存池,earlySingletonObjects-三级缓存池,他们的类型全都是map,key就是beanName
- 从一级缓存取singletonObjects到则直接返回
- 从一级缓存去不到,如果运行循环引用,就从三级缓存池earlySingletonObjects中取,取到了直接返回
- 从二级缓存取不到,就从二级缓存singletonFactories中取,如果去到了,就调用取出来的ObjectFactory对象singletonFactory 的getObject方法,返回实例化后初始化前的bean,并且放入三级缓存,从二级缓存中删除
这里为什么要有三级缓存呢,而且二级缓存取出来的不是Object,而是ObjectFactory?这里先把问题留着,我们可以往下看,在进行提前暴露处理时,看看放入singletonFactories的ObjectFactory对象里面getObject方法的具体实现,就会有答案。
是否循环依赖依赖的判断
如果从缓存总没取到bean,就会进入doCreateBean方法,进行bean的创建在bean创建完成以后,会有一步是否运行循环依赖的判断
/**
* createBeanInstance(beanName, mbd, args)实例化后,初始化前
* 判断是否支持循环引用,是否单例 && 支持循环引用 && 正在创建中(beanName在singletonsCurrentlyInCreation中)
* this.allowCircularReferences默认为true
* 这里为了解决循环引用,先缓存一个工厂,存放实例化后初始化前的单例
* org.springframework.beans.factory.ObjectFactory<T>
* T getObject()
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
- bean是否单例模式,默认肯定是单例
- 支持循环依赖,默认也是支持的
- bean是否正在创建中,这个是在调用creatBean方法前,会先把他的beanName放入一个set的集合(singletonsCurrentlyInCreation)中,标记为正在创建
所以如无意外,肯定成立
条件成立成立举进入提前暴露的处理阶段
提前暴露处理
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/*在二级缓存中,存放当前bean对应的工厂*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
addSingletonFactory就是把当前正在创建的bean提前暴露的处理,key是beanName,value是ObjectFactory对象
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
/**
* singletonObjects是BeanFactory中的三级缓存,Map<String, Object>
* 专门缓存ObjectFactory,也就是俗称的Bean半成品,
* 实际上是个工厂,调用getObject就会返回该创建中的bean
*/
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
/*把ObjectFactory保存到singletonFactories中 */
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
回到刚刚的地方,可以看到ObjectFactory的getObject方法,这里调用的是getEarlyBeanReference方法
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
那么到时候从二级缓存获取到该ObjectFactory对象后,调用getObject方法时,就会去调用getEarlyBeanReference方法,那么我们看看getEarlyBeanReference的具体操作
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
/*判断:不是一个合成的Bean && BeanFactory中存在InstantiationAwareBeanPostProcessors*/
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
/*遍历所有的SmartInstantiationAwareBeanPostProcessor,执行getEarlyBeanReference方法,返回一个有可能被修改后的bean */
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 所以利用SmartInstantiationAwareBeanPostProcessor可以改变一下提前暴露的对象
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
可以看到,他不是单纯的返回该bean。在返回该bean前,会先进行bean后置处理器的处理。这里所有的SmartInstantiationAwareBeanPostProcessor接口的实现类的getEarlyBeanReference方法可以得到回调。我们随便挑一个他的实现了看看
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
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;
}
// 如果该类有advice则创建proxy.
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;
}
可以看到,这里返回的有可能是个代理对象,那么我么取到的就不是原来的bean,而是原来bean的代理对象了。
这也回答了刚刚那个问题:
这里为什么要有三级缓存呢,而且二级缓存取出来的不是Object,而是ObjectFactory?这里先把问题留着,我们可以往下看,在进行提前暴露处理时,看看放入singletonFactories的ObjectFactory对象里面getObject方法的具体实现,就会有答案。
二级缓存存的是个ObjectFactory,那是因为调用他的getObject方法,返回的不一定是原来的bean,spring会在里面进行一些bean后置处理器的回调工作,允许修改该bean,或返回一个代理对象。getObject后返回的对象,又存的三级缓存中,从二级缓存删除,是因为不再进行重复的回调,这里返回经过处理后的对象,以后就从三级缓存中取了,没有必要进行重复处理。
属性注入触发getBean的位置
在doCreatBean方法中,创建完该bean,提前暴露完后。就会进行属性注入
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
// 并且标注了@PostConstruct的方法,也会在此调用,属于初始化回调
populateBean(beanName, mbd, instanceWrapper);
进入populateBean(beanName, mbd, instanceWrapper),首先声明,下面的方法有点长,因为涉及到不用类型的属性注入,不用从头到尾看,我们挑其中一个方法看就行了
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
// InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 调用InstantiationAwareBeanPostProcessor实现类的postProcessAfterInstantiation方法
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
return;
}
}
}
// bean 实例的所有属性都在这里了
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 如果自动装配类型为1-byName 或 2-byType 则进入此分支 但这里是标签形式的,不是注解@Autowire
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 1-AUTOWIRE_BY_NAME 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 2-AUTOWIRE_BY_TYPE 通过类型装配。复杂一些
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
/* 通过BeanPostProcessor完成注解版的自动装配 */
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor
// 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
// 设置 bean 实例的属性值
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
我们看autowireByName(beanName, mbd, bw, newPvs)方法,其他的可以忽略
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireByName
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
/**
* 属性注入,getBean获取依赖的Bean,有可能没有,需要创建
* 有可能已经创建完成,直接从一级缓存singleObjects中获取,
* 或者涉及到循环引用,从三级缓存SingletonFactoryes中获取
*/
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
/*注册一下依赖关系*/
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
...
}
}
else {
if (logger.isTraceEnabled()) {
...
}
}
}
}
可以看到里面有调用了getBean方法,获取或创建依赖的bean。
这时就会进行依赖的bean的创建,然后依赖的bean也走了相同的流程,在进入原来的bean的getBean方法,就可以从二级缓存中获取到该bean的ObjectFactory对象,然后调用getObject方法,获取到该bean的半成品。
- A依赖了B,B又依赖A
- getBean(A),创建A
- 判断符合循环依赖条件,把A的ObjectFactory对象放入二级缓存,这个对象的getObject方法,会返回A
- 进行属性注入
- 发现依赖了B,getBean(B),进行B的创建
- B也走了上面1-5步
- B 依赖了 A,所以A又调用 getBean(A)
- 这是二级缓存中已经存了A的ObjectFactory,就调用ObjectFactory的getObject方法,返回A,不再继续往下进行实例化
- B 先完成属性注入和初始化回调
- A 也完成属性注入和初始化回调
一般循环依赖分析到这里就结束了,但其实下面还有一步
循环引用完成后对bean的类型进行判断
在doCreateBean方法中差不多结尾处,有这么一段长长的方法
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
/**
* 这里也涉及循环引用的问题:
* 此时该bean已经实例化完成,执行了BeanPostProcesser的两个回调方法,
* 有可能该Bean的类型已经改变,也就是说和他实例化时的类型不一致,
* 因为循环引用是在该bean在实例化后初始化前提前暴露,让别的bean引用而完成的
* 此时已经是该bean初始化完成,如果类型不一致,又检测到有其他已经创建完成的bean依赖了这个bean,就会报错
*/
if (earlySingletonExposure) {
// 尝试从缓存中获取单例,注意后面的参数为false,表示不从第三级缓存singletonFactories中获取,为什么呢?因为这里不允许循环依赖
Object earlySingletonReference = getSingleton(beanName, false);
//如果不为null,就会进入if条件中,因为earlySingletonReference不为null,说明存在循环引用,
//为什么呢?因为第一个处理的时候,会将引用放到singletonFactories缓存中,当循环依赖注入的时候,
//会通过singletonFactories中拿到提前暴露的引用,然后放到第二级缓存earlySingletonObjects中。
//所以,在这里拿到了earlySingletonReference,表明存在循环引用。
if (earlySingletonReference != null) {
//如果相等,那么就什么也不做,将earlySingletonReference返回回去即可
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
/**
* 下面就是类型不相等的处理
* 类型不相等 && 已经有创建完成的bean依赖此Bean
* 满足这两个条件,就报错
*/
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
因为在循环引用中,先完成初始化的bean引用到的bean是未完成初始化的bean,而初始化回调有可能修改了该bean的类型,但是先完成初始化的bean因为已经完成了实例化和初始化的整个工作,可以认为已经投入使用中了,这时是不允许他的引用的对象类型发生改变的,否则先完成初始化的bean所引用的bean的类型,跟单例缓存池中的存放的类型就不一致了,也就是不是同一个对象了。