Spring源码解析(五) -- 解决循环依赖

在上一节Spring源码解析(四)中,有一些代码并没有仔细分析。而这些代码都和spring解决循环依赖相关的。比较重要的有两处

第一处在 AbstractAutowireCapableBeanFactory的 doCreateBean方法 

if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        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.
        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<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            if (exposedObject != null) {
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
        }

注意在  createBeanInstance首先实例化一个对象之后,和对这个对象属性值进行填充之前,spring做了一件事。

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<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

把这个空的对象先暴露到一个缓存中,这里就涉及到一个概念,spring的三级缓存。接下来就通过三级缓存和 循环依赖的概念说明下spring是怎么解决循环依赖的。

  1 解决循环依赖的原理

  Spring循环依赖的理论依据其实是Java基于引用传递,当我们获取到对象的引用时,对象的field或者或属性是可以延后设置的。

  Spring单例对象的初始化其实可以分为三步:

  • createBeanInstance, 实例化,实际上就是调用对应的构造方法构造对象,此时只是调用了构造方法,spring xml中指定的property并没有进行populate
  • populateBean,填充属性,这步对spring xml中指定的property进行populate。@Autowired,@Resource 自动注入都在这里执行的。
  • initializeBean,调用spring xml中指定的init方法,或者AfterPropertiesSet方法。
    会发生循环依赖的步骤集中在第一步和第二步。

  2 三级缓存

  “三级缓存”主要是指  DefaultSingletonBeanRegistry 中的三个缓存

  一级 singletonObjects, 二级 earlySingletonObjects ,三级 singletonFactories

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

  singletonObjects指单例对象的cache,singletonFactories指单例对象工厂的cache,earlySingletonObjects指提前曝光的单例对象的cache。

  3 解决过程源码

  在Spring源码解析(四) 中,分析过了Bean创建的过程,首先Spring会尝试从缓存中获取,这个缓存就是指singletonObjects,主要调用的方法是:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      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);}

  首先注意两个对象 

  1  isSingletonCurrentlyInCreation 判断是否当前bean正在创建

  2  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); ObjectFactory又可以成为三级缓存

  判断是否正在创建的逻辑也是在 DefaultSingletonBeanRegistry这个类里,可以说这个类包办了解决循环依赖的全部功能。

public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }

/** Names of beans that are currently in creation */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));

  我们再看看这两个变量是什么时候被赋值的。

  其实这两个变量是在同一个方法里被赋值的,在AbstractBeanFactory的doGetBean方法中,如果一个bean是第一次被创建,那么就会执行到

if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            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);
                }

  我们继续看 

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
        synchronized (this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName,
                            "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                            "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<Exception>();
                }
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {
                    // Has the singleton object implicitly appeared in the meantime ->
                    // if yes, proceed with it since the exception indicates that state.
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw ex;
                    }
                }
                catch (BeanCreationException ex) {
                    if (recordSuppressedExceptions) {
                        for (Exception suppressedException : this.suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                }
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);//此时该bean所有的步骤都走完了,包括成员变量的填充,所以就没必要再要二级和三级缓存了,只需要保留一级缓存
                }
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }

  beforeSingletonCreation就是会把这个beanName加入到 singletonsCurrentlyInCreation 这个set中,而 afterSingletonCreation 会从singletonsCurrentlyInCreation 中删除这个beanName。

  我们继续看 getSingleton会执行  singletonFactory.getObject();而这个逻辑是在

new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {
                                return createBean(beanName, mbd, args);
                            }

  所以继续分析AbstractAutowireCapableBeanFactory的 createBean,在createBean中真正干活的是 doCreateBean。

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

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
        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.
        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<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

  经过createBeanInstance的调用后,bean已经被创建出来了,只是属性值还未填充,也就是说他还只是一个空对象。

  然后会执行

 addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });

  就在这里设置了三级缓存this.singletonFactories.put(beanName, singletonFactory);

  此处就是解决循环依赖的关键,这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来的。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。

  最后再看下三级缓存在哪里被使用的,如果三级缓存里有这个bean那么就不用再创建了,直接拿到这个bean

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

        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            if (logger.isDebugEnabled()) {
                if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                            "' that is not fully initialized yet - a consequence of a circular reference");
                }
                else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }

4 为什么是三级缓存

  为什么采用三级缓存呢,以下是我个人的理解。首先这三个缓存的作用不同。

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

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

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

singletonFactories 的value部分存的是ObjectFactory,只有在调用getSingletion时,会执行ObjectFactory的getObject方法,并存入earlySingletonObjects。
注意一下 singletonObjects 和 earlySingletonObjects初始大小的不同。

earlySingletonObjects在一个bean完全完成了初始化后就会清理,所以没必要有太大的容量。

而 singletonObjects经过我的观察后,只有在spring容器 AbstractApplicationContext 调用 close后才会进行清理,也就是说在spring容器的生命周期里他是一直存在的。
因此总结下,singletonFactories只会被执行一次,执行过后 实例化的bean 存入 earlySingletonObjects,并清理singletonFactories。

earlySingletonObjects在创建bean过程中,getSingleton中会被调用,如果一个bean已经存在在 earlySingletonObjects,则不会继续走创建bean流程。并且在bean初始化完成后被清理。
生命周期比ObjectFactory能长一点。
singletonObjects 生命周期是最长的,因此它才是一级缓存。

earlySingletonObjects经过观察它的生命周期是一个bean第一次被调用getSinfleton之后,三级缓存就会清除,放入二级缓存,这是它的开始。它的结束是该bean完全初始化完毕。

所以,一种可能的场景就是A 包括了B,C,B和C都依赖A。A初始化的时候,会将自己先暴露到三级缓存。这样B在初始化自己的时候,发现要依赖A,此时第一次调用三级缓存,同时A从三级缓存

就到了二级缓存。A又发现自己需要依赖C,就初始化C,然后C发现自己依赖A,此时就会调用getSingleton,这个是就是从二级缓存拿的。如果A所有属性都填充好了,就会销毁二级缓存,只保留一级缓存。

5 为什么构造方法的循环依赖无法解决

  有之前的只是铺垫,这个问题理解起来就容易多了。ClassA初始化时,在实例化之前会把bean name放到Set<String> singletonsCurrentlyInCreation 。然后当执行ClassA的构造函数时,发现要依赖ClassB。在实例化ClassB时,又需要实例化ClassA,结果发现A的bean并不在缓存里,但是还在singletonsCurrentlyInCreation 里。这就发生了bean同时创建的异常。

原文地址:https://www.cnblogs.com/juniorMa/p/13785583.html