Spring注入与循环依赖

Spring中如何解决循环依赖,简单举个下面这样例子

  • A类中注入了B类对象
  • B类中注入了A类对象

 如果是通过构造函数注入,那么在初始化时的时候会报循环注入。A初始化时B可能尚未初始化。

反之,如果是通过get set这种注入或者@Autowired 注入,并且是singelton(默认)而非prototype则不会报错。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。spring通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean。



protected void beforeSingletonCreation(String beanName) {  
        if (!this.inCreationCheckExclusions.containsKey(beanName)  
                && this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {  
            throw new BeanCurrentlyInCreationException(beanName);  
        }  
    }  

1.从源码中可以看出,A实例化时会去singletonsCurrentlyInCreation写入A,A中依赖B因此,需要实例化B,B中依赖A,因此需要实例A,而A之前已经在Increation,因此会报错。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
        // Instantiate the bean.
        //.....


        // 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.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory() {
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // ......
    }



protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            
            synchronized (singletonObject) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                 
                if (singletonObject == null && allowEarlyReference) {
                     
                    ObjectFactory objectFactory = this.singletonFactories.get(beanName);
                    if (objectFactory != null) {
                        singletonObject = objectFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT) ? singletonObject : null;
    }  

2.采用set方法时,Spring略有不同,A实例化时会将一个 A的实例引用写入objectFactory中。执行setB时去实例化B,B的setA调用getSingleton(A,true),因为A 实例还在创建中,会接着往下执行,最终通过objectFactory返回A的实例引用,之后删除factory,缓存A的引用。

猜你喜欢

转载自my.oschina.net/u/2433649/blog/823794