Spring解决循环依赖的思路

时间:2022-07-24
本文章向大家介绍Spring解决循环依赖的思路,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Spring解决循环依赖的思路

一. 什么是循环依赖

循环依赖也就是循环引用,指两个或多个对象互相持有对方的引用。通俗地说,假设在Spring中有3个Service Bean,分别为ServiceA、ServiceB和ServiceC,如果ServiceA引用了ServiceB,ServiceB引用了ServiceC,而ServiceC又引用了ServiceA,最终形成可一个环,这样就出现了循环依赖。

二. Spring如何解决循环依赖

对Spring来说循环依赖,有以下几种:

  1. Prototype类型Bean的循环依赖
  2. 构造器循环依赖
  3. setter循环依赖

对于第1类和第2类的循环依赖,Spring的处理是不解决,直接抛出BeanCurrentlyInCreationException异常。

因此,Spring只处理Singleton类型的Bean的setter循环依赖。其处理思路大概为:对于循环依赖的Bean,提前暴露一个单例工厂ObjectFactory,从而使得其他Bean能引用到该Bean。以前面所说的三个Service为例,具体步骤如下:

  1. Spring 容器创建单例ServiceA,首先根据无参构造器创建Bean,并提前暴露一个 “ObjectFactory”,表示一个创建中的Bean,并将ServiceA放到“当前正在创建的Bean池”中,然后进行 setter注入ServiceB。
  2. ServiceB通过同样的方式,暴露一个ObjectFactory,并将ServiceB放入“当前正在创建的Bean池”中,然后进行setter注入ServiceC。
  3. ServiceC也通过同样的方式,暴露ObjectFactory并将Bean入池,接下来在注入ServiceA的时候,发现ServiceA处于位于正在创建池中,说明出现了循环依赖,此时由于ServiceA已经提前暴露了一个ObjectFactory,则ServiceC会注入ServiceA工厂返回的正在创建中的对象。
  4. 最后通过setter注入ServiceB和ServiceA,完成依赖创建过程。

三. 源码分析

说了这么多理论,下面来分析下源码。我们使用Spring时的一个基本操作就是Bean的获取,那么我们从AbstractBeanFactory的getBean()方法入手:

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

getBean()只是一个接口方法,核心逻辑在doGetBean()中:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    //解析beanName
    final String beanName = transformedBeanName(name);
    Object bean;

    //直接从缓存中或者singletonFactories中对应的ObjectFactory获取
    //检查缓存中或者实例工厂中是否有对应的实例,这样处理是为了解决单例Bean循环依赖的问题
    //在创建单例Bean的过程中会存在依赖注入的情况,而在依赖注入过程中,为了避免循环依赖,Spring的处理是:
    //不等Bean创建完成,就提前曝光创建Bean的ObjectFactory,也就是将ObjectFactory加入到缓存中,
    //一旦一个Bean创建时需要依赖上一个Bean,则直接从缓存中获取ObjectFactory
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                             "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        //返回对应的实例,因为从缓存中获取的Object未必是Bean本身,可能是FactoryBean之类的,需要调用这个方法获取真正的Bean
        //有时会返回Bean指定方法所创建的对象而不是Bean本身,如FactoryBean
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        //Spring只处理Singleton类型Bean的循环依赖
        //对于Prototype类型如果存在循环依赖,直接抛出BeanCurrentlyInCreationException
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        //如果当前容器的BeanDefinition列表不存在Bean的定义,且父容器不为空,则尝试从parentBeanFactory中加载Bean
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

        //如果不仅仅是做类型检查,则是要创建Bean,则先将Bean标记为已创建状态
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            //获取Bean的定义——RootBeanDefinition
            //如果指定的Bean是子Bean的话,则同时会合并父Bean的属性
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            //如果存在依赖的Bean,则递归实例化所有依赖的Bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    //缓存依赖调用
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            //所有依赖Bean已经实例化完成,开始实例化自身

            //SingletonBean的创建
            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);
            }

            //Prototype的创建
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            //其他Scope类型Bean的创建
            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                                                    "Scope '" + scopeName + "' is not active for the current thread; consider " +
                                                    "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                                                    ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    //类型检查:如果传入的requiredType不为空,则对创建好的Bean进行类型校验,如果不满足类型则抛出BeanNotOfRequiredTypeException
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

代码的核心部分我已经加了注释。在获取Bean时,首先会调用getSingleton()方法,因为Spring会将所有Singleton类型的Bean缓存起来,因此首先尝试从缓存中获取。而循环依赖的处理也在这个方法中。点进去看一下:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //首先从singletonObject缓存中获取,如果存在直接返回
    Object singletonObject = this.singletonObjects.get(beanName);

    //如果缓存中不存在,则检查singletonsCurrentlyInCreation,是否该beanName正在创建
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {

        //如果singletonsCurrentlyInCreation中存在beanName,说明该Bean正在创建
        //即出现了循环依赖的情况
        synchronized (this.singletonObjects) {
            //尝试从earlySingletonObjects中获取Bean
            singletonObject = this.earlySingletonObjects.get(beanName);

            //如果earlySingletonObjects中也不存在,且允许提前暴露Bean,则从singletonFactories中获取Bean对应的ObjectFactory
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);

                //如果Bean对应的ObjectFactory存在,则使用ObjectFactory创建Bean,将Bean加入到earlySingletonObjects中
                //并且从singletonFactories中移除该singletonFactory
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

刚方法主要做了以下处理:

  1. 首先尝试从singletonObjects缓存中获取Bean,如果获取到了,说明Bean已经创建完成,直接返回即可。
  2. 缓存中不存在,则检查是否该Bean正在创建,这是解决循环依赖的关键。Spring通过singletonsCurrentlyInCreation这个Set保存了所有正在创建中的beanName。如果在创建一个Bean时,在singletonsCurrentlyInCreation找到了这个Bean的name,则说明出现了循环依赖。
  3. 首先尝试从earlySingletonObjects中获取暴露的创建中的对象,如果不存在,再尝试从singletonFactories中获取提前暴露的对象工程BeanFactory,并调用其getObject()方法,实例化一个提前暴露的正在创建中的对象并放入earlySingletonObjects,然后返回这个创建中的对象。

可以看到,Spring解决循环依赖的方式就是"提前暴露法",在循环引用时,引用提前暴露的正在创建中的对象而非真正实例化完成的对象。

那么singletonFactory中的BeanFactory是在何时创建的呢?搜索调用链,可以看到在AbstractAutowireCapableBeanFactory的doCreateBean()方法中:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    throws BeanCreationException {

    //实例化Bean,大部分情况都是调用其无参构造器
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }

    //允许MergedBeanDefinitionPostProcessor修改BeanDefinition
    synchronized (mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                                "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    //将刚刚实例化完成的Bean,以ObjectFactory的形式放入singletonFactories中,以解决循环依赖的问题
    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));
    }

    ...
}

可以看到,在创建Bean的过程中,一旦实例化完成,就将Bean以ObjectFactory的形式放入singletonFactories中,以解决循环依赖的问题。此时的Bean还未进行属性的赋值和依赖的注入,就是一个空壳。

而在Bean创建完成后,会将其对应的ObjectFactory移除,代码如下:

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);
    }
}

四. 总结

至此,Spring的循环依赖解决思路基本描述完成。可以看到,整体的处理方式还是很巧妙的。主要流程总结如下:

  1. 创建Bean过程中,将beanName放入singletonsCurrentlyInCreation正在创建池中,并创建对应的ObjectFactory放入对象工厂缓存池。
  2. 解析Bean依赖过程中,如果发现存在了循环依赖,则直接引用ObjectFactory所创建的提前暴露的Bean。
  3. Bean的创建结束后,将其从singletonsCurrentlyInCreation中移除,并删除对应的ObjectFactory。

整个过程中,Spring对缓存的处理也很巧妙,现将常用的缓存总结如下(DefaultSingletonBeanRegistry类中):

/**
	 * 用于保存所有已创建的Singleton Bean
	 * key:beanName
	 * value:Singleton Bean
	 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/**
	 * 用于保存创建Bean对应的ObjectFactory工厂
	 * key:beanName
	 * value:Bean对应的ObjectFactory
	 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/**
	 * 用于保存提前暴露出的Bean,与singletonObjects不同的是,这里的Bean可能还未创建完成,但是通过getBean()也能够获取到,主要是为了解决循环依赖的问题
	 * 当Bean创建完成后,会从该缓存中移除
	 * key:beanName
	 * value:提前暴露出的Bean
	 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);


/**
	 * 用于保存所有已经注册号的beanName
	 */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);