spring 源代码 循环依赖

    xiaoxiao2021-03-25  77

    在使用spring的场景中,有时会碰到如下的一种情况,即bean之间的循环引用。即两个bean之间互相进行引用的情况。这时,在spring xml配置文件中,就会出现如下的配置:

    1 2 < bean  id = 'beanA'  class = 'BeanA'  p:beanB-ref = 'beaB' /> < bean  id = 'beanB'  class = 'BeanB'  p:beanA-ref = 'beaA' />

    并且,在一般情况下,这个配置在现有的spring3.0中是可以正常工作的,前提是没有对beanA和beanB进行增强。但是,如果任意一方进行了增强,比如通过spring的代理对beanA进行了增强,即实际返回的对象和原始对象不一致的情况,在这种情况下,就会报如下一个错误:

    1 2 3 4 5 6 '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 ' + ''getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.'

    这个错误即对于一个bean,其所引用的对象并不是由spring容器最终生成的对象,而只是一个原始对象,而spring不允许这种情况出现,即持有过程中间对象。那么,这个错误是如何产生的,以及在spring内部,是如何来检测这种情况的呢。这就得从spring如何创建一个对象,以及如何处理bean间引用,以及spring使用何种策略处理循环引用问题说起。

    这里会涉及到在spring内部所使用的两个内部属性,singletonFactories和earlySingletonObjects,这两个属性在类DefaultSingletonBeanRegistry中被定义,定义如下:

    1 2 3 4 5 /** Cache of singleton factories: bean name --> ObjectFactory */      private  final  Map singletonFactories =  new  HashMap();      /** Cache of early singleton objects: bean name --> bean instance */      private  final  Map earlySingletonObjects =  new  HashMap();

    官方对此的属性定义不是很明确,这里我们可以这样来理解。

    singletonFactories,用于存储在spring内部所使用的beanName->对象工厂的引用,一旦最终对象被创建(通过objectFactory.getObject()),此引用信息将删除earlySingletonObjects,用于存储在创建Bean早期对创建的原始bean的一个引用,注意这里是原始bean,即使用工厂方法或构造方法创建出来的对象,一旦对象最终创建好,此引用信息将删除

    从上面的解释,可以看出,这两个对象都是一个临时工。在所有的对象创建完毕之后,此两个对象的size都为0。

    那么再来看下这两个对象如何进行协作:

    方法1:

    01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 /**  * Add the given singleton factory for building the specified singleton       * if necessary.       *

    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)) {                  this .singletonFactories.put(beanName, singletonFactory);                  this .earlySingletonObjects.remove(beanName);                  this .registeredSingletons.add(beanName);              }          }      }

    方法2:

    01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25   /**       * Return the (raw) singleton object registered under the given name.       *

    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 null if none found       */      protected  Object getSingleton(String beanName,  boolean  allowEarlyReference) {          Object singletonObject =  this .singletonObjects.get(beanName);          if  (singletonObject ==  null ) {              synchronized  ( this .singletonObjects) {                  singletonObject =  this .earlySingletonObjects.get(beanName);                  if  (singletonObject ==  null  && allowEarlyReference) {                      ObjectFactory singletonFactory =  this .singletonFactories.get(beanName);                      if  (singletonFactory !=  null ) {                          singletonObject = singletonFactory.getObject();                          this .earlySingletonObjects.put(beanName, singletonObject);                          this .singletonFactories.remove(beanName);                      }                  }              }          }          return  (singletonObject != NULL_OBJECT ? singletonObject :  null );      }

    方法3:

    01 02 03 04 05 06 07 08 09 10 11 12 13 14 /**       * Add the given singleton object to the singleton cache of this factory.       *

    To be called for eager registration of singletons.

          * @param beanName the name of the bean       * @param singletonObject the singleton object       */      protected  void  addSingleton(String beanName, Object singletonObject) {          synchronized  ( this .singletonObjects) {              this .singletonObjects.put(beanName, (singletonObject != null  ? singletonObject : NULL_OBJECT));              this .singletonFactories.remove(beanName);              this .earlySingletonObjects.remove(beanName);              this .registeredSingletons.add(beanName);          }      }

    方法1和方法2中的官方注释都很明显地显示了,针对于循环引用的处理,即能够处理循环引用问题。

    转载请注明原文地址: https://ju.6miu.com/read-22556.html

    最新回复(0)