Spring中循环引用的处理-1


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<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>();
 
     /** Cache of early singleton objects: bean name --> bean instance */
     private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>();

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

  • 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.
      * <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)) {
                 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.
      * <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</code> 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.
      * <p>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中的官方注释都很明显地显示了,针对于循环引用的处理,即能够处理循环引用问题。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值