什么是循环依赖

循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A,由于对象之间的依赖关系造成了死循环。

Spring中循环依赖场景有:

  • 构造器的循环依赖
  • field属性的循环依赖

Spring怎么解决循环依赖

Spring循环依赖主要基于Java引用传递,当获取到对象时,对象的field或者属性可以延后设置

创建Bean

    /**     * Actually create the specified bean. Pre-creation processing has already happened     * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.     * <p>Differentiates between default bean instantiation, use of a     * factory method, and autowiring a constructor.     * @param beanName the name of the bean     * @param mbd the merged bean definition for the bean     * @param args explicit arguments to use for constructor or factory method invocation     * @return a new instance of the bean     * @throws BeanCreationException if the bean could not be created     * @see #instantiateBean     * @see #instantiateUsingFactoryMethod     * @see #autowireConstructor     * 实际创建指定的bean。 预创建处理已经发生     * 在这一点上,例如 检查{@code postProcessBeforeInstantiation}回调。     * <p>区分默认的bean实例化,使用     * 工厂方法,并自动装配构造函数。     * @param beanName bean的名称     * @param mbd该bean的合并bean定义     * @param args用于构造函数或工厂方法调用的显式参数     * @返回bean的新实例     * @throws BeanCreationException如果无法创建bean     * @请参阅#instantiateBean     * @see #instantiateUsingFactoryMethod     * @请参阅#autowireConstructor     */    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)            throws BeanCreationException {        // Instantiate the bean.        BeanWrapper instanceWrapper = null;        if (mbd.isSingleton()) {             //从缓存中移除bean,因为要创建新的bean了            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);        }        if (instanceWrapper == null) {              //根据指定bean的使用策略创建新的实例,如:工厂方法,构造函数自动注入,简单初始化            instanceWrapper = createBeanInstance(beanName, mbd, args);        }        final Object bean = instanceWrapper.getWrappedInstance();        Class<?> beanType = instanceWrapper.getWrappedClass();        if (beanType != NullBean.class) {            mbd.resolvedTargetType = beanType;        }        // Allow post-processors to modify the merged bean definition.        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;            }        }        // Eagerly cache singletons to be able to resolve circular references        // even when triggered by lifecycle interfaces like BeanFactoryAware.         //是否需要提早曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖        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");            }             //为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂,其他bean引用此bean时直接从ObjectFactory获取bean             //getEarlyBeanReference对bean再一次依赖引用,主要应用SmartInstantiationAware BeanPost Processor其中我们熟悉的AOP就是在这里将advance动态织入bean中的,如果没有就直接返回bean,不做任何处理            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));        }        // Initialize the bean instance.        Object exposedObject = bean;        try {             //对bean进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归给初始依赖bean            populateBean(beanName, mbd, instanceWrapper);             //调用初始化方法,如init-method            exposedObject = initializeBean(beanName, exposedObject, mbd);        }        catch (Throwable ex) {            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {                throw (BeanCreationException) ex;            }            else {                throw new BeanCreationException(                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);            }        }        if (earlySingletonExposure) {            Object earlySingletonReference = getSingleton(beanName, false);             //earlySingletonReference只有在检测到有依赖循环的情况下才会不为空            if (earlySingletonReference != null) {                  //如果exposedObject没有在初始化方法中被改变,也就是没有被增强                if (exposedObject == bean) {                    exposedObject = earlySingletonReference;                }                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {                    String[] dependentBeans = getDependentBeans(beanName);                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);                    for (String dependentBean : dependentBeans) {                          //检测依赖                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {                            actualDependentBeans.add(dependentBean);                        }                    }                      //因为bean创建后其所依赖的bean一定是已经创建的,actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有创建完,也就是存在循环依赖                    if (!actualDependentBeans.isEmpty()) {                        throw new BeanCurrentlyInCreationException(beanName,                                "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.");                    }                }            }        }        // Register bean as disposable.        try {              //根据scopse注册bean            registerDisposableBeanIfNecessary(beanName, bean, mbd);        }        catch (BeanDefinitionValidationException ex) {            throw new BeanCreationException(                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);        }        return exposedObject;    }

以上是Spring创建bean的方法,代码很多但是核心思路就是实例化,填充属性,初始化,而循环依赖主要发生在实例化和填充属性这两部分

        //根据指定bean的使用策略创建新的实例,如:工厂方法,构造函数自动注入,简单初始化        instanceWrapper = createBeanInstance(beanName, mbd, args);        //对bean进行填充,将各个属性值注入,其中,可能存在依赖于其他bean的属性,则会递归给初始依赖bean        populateBean(beanName, mbd, instanceWrapper);        //调用初始化方法,如init-method        exposedObject = initializeBean(beanName, exposedObject, mbd);

Spring为了解决循环依赖,设置了三级缓存

一级缓存singletonObjects

用于保存BeanName和创建bean实例之间的关系,beanName -> bean instance

private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

二级缓存earlySingletonObjects

保存提前曝光的单例bean对象

private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

三级缓存singletonFactories

保存beanName和创建bean实例之间的关系,与singletonObjects不同的地方在于,当一个单例bean被放到这里面后,bean在创建过程中,可以通过getBean方法获取到,目的是用来检测循环引用

private final Map<String, Object> singletonFactories = new HashMap(16);

在创建bean的时候,首先从缓存中获取单例的bean,这个缓存就是singletonObjects,如果获取不到且bean正在创建中,就再从earlySingletonObjects中获取,如果还是获取不到且允许从singletonFactories中通过getObject拿到对象,就从singletonFactories中获取,如果获取到了就存入earlySingletonObjects并从singletonFactories中移除。

getSingleton

    //用于保存BeanName和创建bean实例之间的关系,beanName -> bean instance    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);    //保存提前曝光的单例bean对象    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);    //保存beanName和创建bean实例之间的关系,与singletonObjects不同的地方在于,当一个单例bean被放到这里面后,bean在创建过程中,可以通过getBean方法获取到,目的是用来检测循环引用    private final Map<String, Object> singletonFactories = new HashMap(16);    //保存当前所有已注册的bean    private final Set<String> registeredSingletons = new LinkedHashSet(256);    /**     * 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} if none found     * 返回以给定名称注册的(原始)单例对象。     * <p>检查已实例化的单例,并允许早期     * 引用当前创建的单例(解析循环引用)。     * @param beanName bean的名称     * @param allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象     * @返回注册的单例对象;如果找不到,则返回{@code null}     */    @Nullable    protected Object getSingleton(String beanName, boolean allowEarlyReference) {         //检查缓存中是否存在实例        Object singletonObject = this.singletonObjects.get(beanName);        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {             //如果为空,且正在创建中,锁定全局变量并进行处理            synchronized (this.singletonObjects) {                  //如果bean正在加载则不处理                singletonObject = this.earlySingletonObjects.get(beanName);                if (singletonObject == null && allowEarlyReference) {                      //当某些方法需要提前初始化的时候会调用addSingletonFactory方法将对于ObjectFactory初始化策略存储在singletonFactories                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);                    if (singletonFactory != null) {                          //调用预设的getObject方法                        singletonObject = singletonFactory.getObject();                          //记录在缓存中earlySingletonObjects和singletonFactories互斥                        this.earlySingletonObjects.put(beanName, singletonObject);                        this.singletonFactories.remove(beanName);                    }                }            }        }        return singletonObject;    }

addSingletonFactory

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

现在有A的field或者setter依赖B的实例对象,同时B的field或者setter依赖了A的实例,A首先开始创建,并将自己暴露到 singletonFactories 中,开始填充属性,此时发现自己依赖B的属性,尝试去get(B),发现B还没有被创建,所以开始创建B,在进行属性填充时初始化A,就从singletonObjects中获取到了初始化但没有任何属性的A,B拿到A后完成了初始化阶段,将自己放到singletonObjects中,此时返回A,A拿到B的对象继续完成初始化,完成后将自己放到singletonObjects中,由A与B中所表示的A的属性地址是一样的,所以A的属性填充完后,B也获取了A的属性,这样就解决了循环的问题。