• [转]spring 学习-bean创建-循环依赖-1


    转载自 https://www.iflym.com/index.php/code/201208280001.html

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

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

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

    "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内部所使用的两个内部属性,singletonFactoriesearlySingletonObjects,这两个属性在类DefaultSingletonBeanRegistry中被定义,定义如下:

    /** 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:

    /**  
    * 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:

    /**
         * 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:

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

  • 相关阅读:
    SilverLight学习篇——框架搭建及实例讲述(huangyezi)
    MVVMLight学习
    MVVMLight学习篇——WPF MVVMLightToolkit(李凤桐)
    MvvmLight学习篇—— Mvvm Light Toolkit for wpf/silverlight系列(子林)
    Erro:Namespace http://schemas.microsoft.com/expression/blend/2008 is not resolved.
    MEF学习篇——MEF程序设计指南(Bēniaǒ)
    Error:The tag 'Label' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'.
    silverlight页面间常用跳转模式
    UIViewController的生命周期以及相互之间通信
    解析:如何快速掌握SQL Server的锁机制
  • 原文地址:https://www.cnblogs.com/Benjious/p/15183070.html
Copyright © 2020-2023  润新知