logo

源码分析:Spring如何解决单例Bean的循环依赖?

作者:李不2021.05.17 16:41浏览量:191

简介:Spring通过ObjectFactory提前暴漏一个创建中的Bean(BeanWrapper).

假设Bean为A,第一次对A进行依赖查找时是查不到beanName对应实例的,因为

● singletonObjects:不存在A对应元素,A完全初始化之后才会放进去。
● singletonsCurrentlyInCreation:也不存在A对应元素!用以标识创建中的状态!

看下getSingleton(String beanName,boolean allowEarlyReference);

/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
             singletonObject = this.earlySingletonObjects.get(beanName);
             if (singletonObject == null && allowEarlyReference) {
                //返回提前暴漏的Bean。之所以能解决循环依赖,就是其他Bean依赖当前BeanA的时候singletonFactories返回了A的beanName关联的Objectfactory,而这个ObjectFactory可以提前暴漏未完全初始化的Bean A实例,其实是一个BeanWrapper对象,尚未填充属性和初始化Bean。
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                   singletonObject = singletonFactory.getObject();
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
                }
             }
          }
   }
    return singletonObject;
}

所以shareInstance返回null,忽略一些无关代码,于是执行到getSingleton(String,ObjectFactory<?>)代码.

//AbstractBeanFactory.java
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
     ....
      Object sharedInstance = getSingleton(beanName, true);
      .....
      // Create bean instance.
        if (mbd.isSingleton()) {
           sharedInstance = getSingleton(beanName, () -> {
            try {
                return 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.
                 destroySingleton(beanName);
                 throw ex;
              }
           });
           bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        .....
        return bean;
}

通过代码细节看到singleObjects中找不到beanName对应的实例,但是后边会根据singletonFactory.getObject()来查找Bean。singletonFactory就是传进来的包含createBean的lambda表达式。但在创建之前需要做一些前置准备,也就是执行beforeSingletonCreation(String beanName);此方法中执行的操作就是“标志A这个Bean在创建中”。即singletonsCurrentlyInCreation.add(String BeanName)方法。

protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
   }
}
//DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    ....
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            ...
            //this.singletonsCurrentlyInCreation.add(beanName)
            beforeSingletonCreation(beanName);
            ...
            try {
                //AbstractAutowireCapableBeanFactory#createBean
               singletonObject = singletonFactory.getObject();
               newSingleton = true;
            }catch(...){}
            finally{
                ...
                //this.singletonsCurrentlyInCreation.remove(beanName)
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {  
               // 实际执行的是
               // protected void addSingleton(String beanName, Object singletonObject) {
               //      synchronized (this.singletonObjects) {
               //          this.singletonObjects.put(beanName, singletonObject);
               //           this.singletonFactories.remove(beanName);
               //           this.earlySingletonObjects.remove(beanName);
               //           this.registeredSingletons.add(beanName);
               //       }
                // }             
               addSingleton(beanName, singletonObject);
            }     
        }
        return singletonObject;
    }

}

创建完Bean以后,即createBean方法执行完毕之后,在finally块中就删除掉Bean A创建中的标识了,即:

afterSingletonCreation(beanName);

实际就是this.singletonsCurrentlyInCreation.remove(beanName);这一行代码起了作用。
Bean A创建完了,但还需要执行下边操作:

 if (newSingleton) {             
               addSingleton(beanName, singletonObject);
 }

这个操作的作用是更新Bean在Spring容器中的缓存状态。


   protected void addSingleton(String beanName, Object singletonObject) {
           synchronized (this.singletonObjects) {
                   //缓存Bean
                this.singletonObjects.put(beanName, singletonObject);
                  //删除beanName关联的用以提前暴漏Bean的ObjectFactory
                 this.singletonFactories.remove(beanName);
                 //删除早期暴漏bean缓存标识
                 this.earlySingletonObjects.remove(beanName);
                 //注册为单例Bean
                 this.registeredSingletons.add(beanName);
             }
  }

在createBean中执行Bean A实例化的主要就是doCreateBean。
这个方法里判断:

  • 单例Bean
  • 允许循环依赖
  • 正在创建中

能满足这个三个条件,则Spring会认为这个此时A是需要提前暴漏的单例Bean。因为只有提前暴漏才能解决循环依赖的问题。那么如何提前暴漏单例Bean A呢?

其实就是给A关联一个ObjectFactory对象。然后再进行Bean的初始化进程即populateBean和initializeBean,最后返回初始化之后的Bean。

那么代码getSingleton(String beanName, ObjectFactory<?> singletonFactory)中singletonFactory.getObject();这一行就返回了。

拿到了createBean之后的Bean A实例对象,相当于Bean A已经创建完成了,那么执行finally里的afterSingletonCreation方法。从singletonsCurrentlyInCreation中删除beanName,毕竟Bean已经创建结束了,就是前边已经提到的finally块中的afterSingletonCreation(beanName);这行代码。

但是本文核心问题来了,如果Bean A依赖了Bean C,那么createBean方法执行时必然会去依赖查找Bean C,而Bean C同样执行getBean方法来实例化和初始化,在这个过程中Bean C如果依赖了Bean A,就形成了A–C—A这样的循环依赖。Bean A虽然还没初始化完成,但是在getBean查找Bean C之前却提前暴漏了自己。也就是 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));这行代码。

//AbstractAutowireCapableBeanFactory
protected Object doCreateBean(
    final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
                                                                throws BeanCreationException {
      .........
    // Eagerly cache singletons to be able to resolve circular references
    // even when triggered by lifecycle interfaces like BeanFactoryAware.
    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));
     }
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
       populateBean(beanName, mbd, instanceWrapper);
       exposedObject = initializeBean(beanName, exposedObject, mbd);
    }catch(...){...}
    if (earlySingletonExposure) {
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
            if (exposedObject == bean) {
                  exposedObject = earlySingletonReference;
            }
            .........
        }
    }
    return exposedObject;
}

重点看下提前暴漏都做了啥?

 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
/**
 * Add the given singleton factory for building the specified singleton
 * if necessary.
 * <p>To be called for eager registration of singletons, e.g. to be able to
 * resolve circular references.
 * @param beanName the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized (this.singletonObjects) {
     if (!this.singletonObjects.containsKey(beanName)) {
         //关键代码,beanName关联singletonFactory
         this.singletonFactories.put(beanName, singletonFactory);
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

给Bean A关联了一个ObjectFactory,也就是getEarlyBeanReference对应的lambda函数对象。放入了singletonFactories中,当Bean C去查BeanA的时候就可以通过getEarlyBeanReference方法获取exposedObject这个早期bean对象。

/**
 * Obtain a reference for early access to the specified bean,
 * typically for the purpose of resolving a circular reference.
 * @param beanName the name of the bean (for error handling purposes)
 * @param mbd the merged bean definition for the bean
 * @param bean the raw bean instance
 * @return the object to expose as bean reference
 */
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
    return exposedObject;
}

看下Bean C怎么依赖查Bean A?

/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   //如果C来查找A,此时会符合if条件
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            //这里C来查A一定查不到,符合下边的if条件
             singletonObject = this.earlySingletonObjects.get(beanName);
             if (singletonObject == null && allowEarlyReference) {
                 //C来查A,singletonFactories是有值的
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                   //调用getEarlyBeanReference返回exposedObject
                   singletonObject = singletonFactory.getObject();
                   //全局也只有此处对earlySingletonObjects进行put
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
                }
             }
          }
   }
    return singletonObject;
}

到这里,基本上已经分析完了关于单例Bean循环依赖的问题,应该还是挺清晰的,总结一下:

Spring通过ObjectFactory提前暴漏一个创建中的Bean(BeanWrapper).给依赖它的Bean使用。让依赖它的Bean的初始化不再需要等待其完全初始化,避免了循环依赖的问题!
————————————————
版权声明:本文为CSDN博主「Jeff.S」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shengqianfeng/article/details/116495968

相关文章推荐

发表评论