Spring循环依赖

304 阅读24分钟

概念

多个bean之间相互依赖,形成了一个闭环。 比如:A依赖于B、B依赖于c、c依赖于A。通常来说,如果问spring容器内部如何解决循环依赖, 一定是指默认的单例Bean中,属性互相引用的场景。

image.png

关于循环依赖,Spring官网说明如下,官网地址:docs.spring.io/spring-fram…

image.png

官网的结论:我们AB循环依赖问题只要A的注入方式是setter且singleton, 就不会有循环依赖问题。

代码演示

public class A {

   private B b;

   public B getB() {
      return b;
   }

   public void setB(B b) {
      this.b = b;
   }

   public A() {
      System.out.println("对象a的构造方法执行..............");
   }
}
public class B {

   private A a;

   public A getA() {
      return a;
   }

   public void setA(A a) {
      this.a = a;
   }

   public B(){
      System.out.println("对象b构造方法执行........");
   }
}

applicationContext.xml配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">


   <bean id="a" class="com.luban.service.A" >
      <property name="b" ref="b"/>
   </bean>

   <bean id="b" class="com.luban.service.B">
      <property name="a" ref="a"/>
   </bean>
</beans>

测试类如下:

public class Test {
   public static void main(String[] args) {
      ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

      A a = ac.getBean("a", A.class);
      B b = ac.getBean("b", B.class);
   }
}

三级缓存

通常所说的三级缓存就是指的是在类DefaultSingletonBeanRegistry中三个Map容器,如下:

//这个就是微观springioc容器 【重点三级缓存中的一级缓存,即单例池】
//存放了已经经历了完整生命周期的Bean对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
//【三级缓存】
   // 存放可以生成Bean工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name --> bean instance */
//【二级缓存】
//存放早期暴露出来的Bean对象,Bean生命周期未结束(属性还未填充完)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  • 第一级缓存〈也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象

  • 第二级缓存: earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)

  • 第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂

循环依赖解决过程如下

  • 1.Spring中一个类创建对象的过程,首先从getSingleton方法中查看Spring一级缓存singletonObjects中是否有该对象,通过该方法中的调用isSingletonCurrentlyInCreation方法判断该对象是否在创建中,什么叫做创建中?即已经实例化了对象,但是还没有给都对象进行属性赋值。如果在创建中,则查看二级缓存中是否有该对象,如果没有接着查看三级缓存。

  • 2. 实例化对象之后,在进行属性赋值之前,即调用populateBean之前,会调用addSingletonFactory方法将对象实例放入到Spring三级缓存singletonFactories中,然后后面进行属性赋值以及初始化,

  • 3. 对象实例化,属性赋值以及初始化完成之后调用addSingleton方法将该对象放入到一级缓存singletonObjects中。

循环依赖的详细步骤如下:

首先进行A实例化,接着将A对象放入到三级缓存singletonFactories中,然后调用populateBean进行属性赋值,发现需要依赖B对象,于是进行B对象的创建,首先getSingleton方法查看缓存中是否存在该对象,不存在则进行创建,实例化B对象之后,调用populateBean进行属性赋值,发现依赖A对象,于是进行A对象的创建,调用getSingleton方法查询一级缓存中没有该对象,但是A对象之前已经实例化过,但是还没有进行属性赋值,即属于创建过程中,于是查询二级和三级缓存中是否有该对象,当然该对象在三级缓存中,于是得到该对象,将该对象从三级缓存中移到二级缓存中;接着回来进行B对象中A属性的赋值,赋值完成之后,进行B对象的初始化,然后调用addSingleton方法将该对象放入到一级缓存singletonObjects中;接着回来进行A对象中B属性的赋值操作,接着进行A对象的初始化,初始化话完成之后调用addSingleton方法将该对象放入到一级缓存singletonObjects中。

涉及的主要方法如下图所示

image.png

源码分析

image.png

image.png

/**
 * 该方法完成IOC容器创建以及初始化工作
 * 该方法中最重要的是第二步和第十一步
 *
 */
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      // STEP 1: 刷新预处理
      //准备工作包括设置启动时间,是否激活标识位,初始化属性源(property,source)配置
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      //用DefaultListableBeanFactory的子类得到的是DefaultListableBeanFactory
      //可以理解为初始化bean工厂

      // STEP 2:
      //        a) 创建IoC容器(DefaultListableBeanFactory)
      //    b) 加载解析XML文件(最终存储到Document对象中)
      //    c) 读取Document对象,并完成BeanDefinition的加载和注册工作
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      //最重要的方法,准备bean工厂
      // STEP 3: 对IoC容器进行一些预处理(设置一些公共属性)
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         //这个方法在当前版本的spring是没有任何代码的,可能spring期待在后面的版本中进行扩展
         //空壳方法
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //比较重要的方法
         //在spring的环境中去执行已经被注册的factory processors
         //设置执行自定义的ProcessorFactory和spring内部自己定义的(ConfigutationClassPoetProcessor)
         //ConfigurationClassPostProcessor就是spring内部自己维护的BeanFactoryPostProcessor
         //下面的方法主要执行ConfigurationClassPostProcessor中的方法
         // STEP 5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理

         /**
          * BeanFactoryPostProcessor是spring的扩展点之一
          * 实现该接口,可以在spring的bean创建之前修改bean的定义属性
          *  spring允许BeanFactoryPostProcessor在容器实例化任何其他bean之前读取它配置的元数据
          *  并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改
          *  可以同时配置多个BeanFactoryPostProcessor,并且通过设置'order'属性来控制各个BeanFactoryPostProcessor
          *  BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的
          *  可以写一个例子来测试以下这个功能
          */
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //上一行的代码已经将一些后置处理器放到bdMap中了,包括自定义的BeanPostProcessor
         // 注册BeanPostProcessor,即后置处理器,一共是7个
         //把bdMap中的所有后置处理器拿出来,
         // 再直接new另外一些后置处理器,一起放到工厂的list中
         // STEP 6: 注册BeanPostProcessor后置处理器
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //不重要,国际化的处理
         // STEP 7: 初始化一些消息源(比如处理国际化的i18n等消息源)
         initMessageSource();

         // Initialize event multicaster for this context.
         //事件处理,用的比较少,不重要
         // STEP 8: 初始化应用事件广播器
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //这是一个空壳方法,里面没有代码
         // STEP 9: 初始化一些特殊的bean
         onRefresh();

         // Check for listener beans and register them.
         //对一些监听器的注册,先放一放
         // STEP 10: 注册一些监听器
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //重点,重点
         //完成bean的实例化
         // STEP 11: 实例化剩余的单例bean(非懒加载方式)
         // 注意事项:Bean的IoC、DI和AOP都是发生在此步骤
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         // STEP 12: 完成刷新时,需要发布对应的事件
         finishRefresh();
      }
}

查看第十一步:finishBeanFactoryInitialization(beanFactory)方法

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   //省去不重要代码

   // Instantiate all remaining (non-lazy-init) singletons.
   //最重要的代码
   //这里调用的DefaultListableBeanFactory中的preInstantiateSingletons
   //实例化所有的单例对象
   beanFactory.preInstantiateSingletons();
}
//真正调用这里,重点
@Override
public void preInstantiateSingletons() throws BeansException {
   if (logger.isDebugEnabled()) {
      logger.debug("Pre-instantiating singletons in " + this);
   }

   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   //从bdMap拿到所有需要初始化的类
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   for (String beanName : beanNames) {
      //这行代码不重要,合并父类的bd,这种应用很少用
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      //肯定会进到if中
      //如果bean不是抽象的,而且是单例的,同时还不是懒加载的,则进行下面的操作
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         //这里判断是不是FactoryBean
         if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               final FactoryBean<?> factory = (FactoryBean<?>) bean;
               boolean isEagerInit;
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                              ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            //重点
            getBean(beanName);
         }
      }
   }
}

image.png

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

   //因为你的beanName有可能加了&,所以要将&移除
   //这里用到的是FactoryBean的知识
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   
   //从三级缓存中获取bean对象,面试重点 spring三级缓存
   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实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   //重点,容器中没有该对象的实例
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      /**
       * 如果是原型,不应该在初始化的时候创建
       * spring当中的标识CurrentlyInCreation标识该类正在创建
       * spring容器循环依赖报错演示BeanCurrentlylnCreationException
       */
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

    
      try {
          
         // Create bean instance.
         //重点重点
         if (mbd.isSingleton()) {
            /**
             * getSingleton相当于从缓存中根据beanName取出对象,
             * 如果取不到,就回调下面的匿名内部类的createBean方法
             */
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  //重点
                  //真正调用AbstractAutowireCapableBeanFactory中的createBean方法
                  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);
         }      
   }
   return (T) bean;
}
  • transformedBeanName 将 name 转换为真正的 beanName(name 可能是 FactoryBean 以 & 字符开头或者有别名的情况,所以需要转化下)
/**
 * 从三个map中拿出单例bean
 * 三个缓存
 *
 * 三级缓存问题 循环依赖问题
 * 三级缓存就是为了解决循环依赖
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //这个singletonObjects就是微观springioc容器
   //从一级缓存中获取单例对象
   Object singletonObject = this.singletonObjects.get(beanName);
   /**
    * isSingletonCurrentlyInCreation
    * 判断当前单理bean是否正在创建中,也就是已经创建了对象实例但是还没有完成属性赋值
    * 比如A的构造器依赖了B对象所以得先去创建B对象,或者A的populateBean过程中依赖了B对象,得先去创建B对象
    * 这是A就是处于创建中的状态
    */
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         //从二级缓存中获取单例bean
         singletonObject = this.earlySingletonObjects.get(beanName);
         //allowEarlyReference是否允许从singletonFactories中通过getObject查到对象
         if (singletonObject == null && allowEarlyReference) {
            //从三级缓存中获取单理bean
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               //从三级缓存移动代理二级缓存
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}
  • 然后第一个通过 getSingleton(beanName) 方法尝试从一级缓存singletonObjects中查找是不是有该实例 sharedInstance,如果没有则调用isSingletonCurrentlyInCreation(beanName)判断该对象是否在创建中,何为创建中?简单的理解就是对象已经实例化,但是还没有填充属性和初始化(单例在 Spring 的同一容器只会被创建一次,后续再获取 bean,就直接从缓存获取即可) isSingletonCurrentlyInCreation(beanName)方法代码如下:
public boolean isSingletonCurrentlyInCreation(String beanName) {
   return this.singletonsCurrentlyInCreation.contains(beanName);
}

image.png

回到上面的 getSingleton(beanName) 方法,如果该对象正在创建中,则尝试从二级缓存earlySingletonObjects中获取,如果二级缓存中还获取不到,则尝试从三级缓存singletonFactory中获取。beanName为a的一开始进来getSingleton(beanName) 时,三个缓存中都没有包含beanName为a的,所以此时返回为null.

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

   //因为你的beanName有可能加了&,所以要将&移除
   //这里用到的是FactoryBean的知识
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   
   //从三级缓存中获取bean对象,面试重点 spring三级缓存
   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实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   //重点,容器中没有该对象的实例
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      /**
       * 如果是原型,不应该在初始化的时候创建
       * spring当中的标识CurrentlyInCreation标识该类正在创建
       * spring容器循环依赖报错演示BeanCurrentlylnCreationException
       */
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

    
      try {
          
         // Create bean instance.
         //重点重点
         if (mbd.isSingleton()) {
            /**
             * getSingleton相当于从缓存中根据beanName取出对象,
             * 如果取不到,就回调下面的匿名内部类的createBean方法
             */
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  //重点
                  //真正调用AbstractAutowireCapableBeanFactory中的createBean方法
                  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);
         }      
   }
   return (T) bean;
}

接着我们继续看第二个包含lamda表达式的getSingleton方法,如下:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
       //尝试从一级缓存中获取bean,此时为null
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         
         //往上面说的存储正在创建中对象的容器singletonsCurrentlyInCreation中添加该beanName
         beforeSingletonCreation(beanName);
          
         try {
            //这行代码是真正创建对象的,该对象已经是一个代理对象了,重点
            /**
             * 后置处理器就是再这里把原生的变成代理对象,去看匿名内部类中的createBean方法
             * 这里其实就是调用外面的lamda表达式中的createBean方法
             */
            singletonObject = singletonFactory.getObject();
            //调用lamda表达式createBean方法创建完对象之后,将该变量置为true
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            
         }
         
         if (newSingleton) {
            //重点,三级缓存解决循环依赖问题
            //实例化完成对象,并且对象设只属性和完成初始化之后
            //及那个该对象放入到一级缓存中
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

这个getSingleton方法主要的逻辑:首先从一级缓存singletonObjects中获取,此时获取不到为null,接着将当前的beanName为a的存入到上面提到的存储存储正在创建中对象的singletonsCurrentlyInCreation中,然后调用singletonFactory.getObject();,本质就是调用外面的lamda表达式中createBean方法创建beanName为a的对象,调用完createBean方法创建对象之后,接着将标识newSingleton置为true,然后调用addSingleton方法将创建出来的对象加入到一级缓存singletonObjects中。

addSingleton方法如下:将创建出来的完整对象(即已经实例化,填充属性以及初始化之后的对象)加入到一级缓存singletonObjects中,然后将二级缓存和三级缓存中删除掉。

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

接着查看createBean方法创建对象,如下:

image.png

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

   //将不重要的代码省略

   try {
      //真正实例化bean(还有填充属性,初始化)的方法在这一行
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isDebugEnabled()) {
         logger.debug("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

接着查看doCreateBean方法

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

   // Instantiate the bean.
   //BeanWrapper把真实对象包装了一层,该类中的getWrappedInstance返回真实对象
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      //开始创建真实对象的包装类,利用反射
      //默认调用无参构造实例化bean
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   //这里从包装类中拿出的是原生对象,而不是代理对象,接着下面的操作把原生对象变成代理对象
   final Object bean = instanceWrapper.getWrappedInstance();
   
   }

   // 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));
   //如果要提前暴露单理bean,则将该bean加入到三级缓存中
   if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      //重要,一定要进去看看
      //把创建出来的对象放入相应的map中
      //将刚创建的bean放入到三级缓存中 singleFactories(key是besnName,value是FactoryBean)
      //singletonFactory是通过lamda表达式获取得到的
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      //赋值属性的,重要
      //主要借助Common和Autowired两个后置处理器来填充属性
      //bean初始化第二步:填充属性(DI依赖注入发生在此步骤)
      populateBean(beanName, mbd, instanceWrapper);
      /**
       * 重点,这里就是把原生对象变成代理对象的地方
       * bean初始化第三步:调用初始化方法,完成bean的初始化,aop发生在此步骤
       * 例如<besn init-method=""></besn>中的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);
      }
   }

   return exposedObject;
}

上述代码中,首先调用createBeanInstance(beanName, mbd, args);底层通过反射创建出a对象,接着调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));将创建出来的对象a加入到三级缓存singletonFactories中,addSingletonFactory方法如下:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      //首先判断一级缓存中是否有对象
      if (!this.singletonObjects.containsKey(beanName)) {
         //首先将关键字为beanName,value为lamda表达式中获取出来的singletonFactory
         //放到三级缓存中
         this.singletonFactories.put(beanName, singletonFactory);
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

注意,() -> getEarlyBeanReference(beanName, mbd, bean)中的getEarlyBeanReference方法如下:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         //提供扩展用的,也就是允许将对象存入三级缓存之前做其他的事情
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

将对象a加入到三级缓存singletonFactory之后,接着对象a调用populateBean(beanName, mbd, instanceWrapper);进行填充属性,如下;

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   
   //省略无关代码

   //获取出所有的property属性值,因为在组装BeanDefinition对象时,将类的属性放入到了PropertyValues中
   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   if (pvs != null) {
      //基于xml方式
      //完成依赖注入
      //PropertyValues pvs:待依赖的属性值集合
      //BeanWrapper bw:实例化后的Bean的包装对象
      //xml方式的属性注入在这里
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

接着查看applyPropertyValues方法如下:

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
   
   //遍历所有A类中属性,依赖的B类属性就在其中
   for (PropertyValue pv : original) {
      if (pv.isConverted()) {
         deepCopy.add(pv);
      }
      else {
         String propertyName = pv.getName();
         Object originalValue = pv.getValue();
         //循环依赖重点,由于依赖B类,所有需要将B类对象先创建出来resolvedValue
         //!!!!重点
         //一位属性中的对象还没有创建,所以不能直接设置属性值,必须先创建属性对象
         Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
         
   // Set our (possibly massaged) deep copy.
   try {
      //将创建出来的B类对象填充到A对象中
      //完成依赖注入
      bw.setPropertyValues(new MutablePropertyValues(deepCopy));
   }
   catch (BeansException ex) {
      
   }
}

上述代码中,首先调用valueResolver.resolveValueIfNecessary处理a对象依赖B类的问题,将会创建出B类对象,接着最后调用bw.setPropertyValues将B类对象作为属性填充到A对象中。

咱们接着看resolveValueIfNecessary方法创建B类对象的过程,如下:

@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
   // We must check each value to see whether it requires a runtime reference
   // to another bean to be resolved.
   if (value instanceof RuntimeBeanReference) {
      RuntimeBeanReference ref = (RuntimeBeanReference) value;
      //重点看该方法
      return resolveReference(argName, ref);
   }
    
   //省略无关代码
}

接着查看resolveReference方法,如下:

@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
   try {
      Object bean;
      String refName = ref.getBeanName();
      refName = String.valueOf(doEvaluate(refName));
      if (ref.isToParent()) {
         if (this.beanFactory.getParentBeanFactory() == null) {
            throw new BeanCreationException(
                  this.beanDefinition.getResourceDescription(), this.beanName,
                  "Can't resolve reference to bean '" + refName +
                        "' in parent factory: no parent factory available");
         }
         bean = this.beanFactory.getParentBeanFactory().getBean(refName);
      }
      else {
         //重点!!!
         //从Spring容器中找属性对象
         //进去之后发现跟刚刚创建对象是一样的过程
         bean = this.beanFactory.getBean(refName);
         this.beanFactory.registerDependentBean(refName, this.beanName);
      }
       
      return bean;
   }
   catch (BeansException ex) {
   }
}

上述代码中,调用this.beanFactory.getBean(refName);创建出B类对象,创建对象流程跟创建A类对象类似,接着查看getBean方法,如下:

image.png

doGetBean => createBean => doCreateBean

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

   
   if (instanceWrapper == null) {
      //开始创建真实对象的包装类,利用反射
      //默认调用无参构造实例化bean
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   //这里从包装类中拿出的是原生对象,而不是代理对象,接着下面的操作把原生对象变成代理对象
   final Object bean = instanceWrapper.getWrappedInstance();
   
   /**
    * 解决循环依赖的关键步骤
    */
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   //如果要提前暴露单理bean,则将该bean加入到三级缓存中
   if (earlySingletonExposure) {
      if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean '" + beanName +
               "' to allow for resolving potential circular references");
      }
      //重要,一定要进去看看
      //把创建出来的对象放入相应的map中
      //将刚创建的bean放入到三级缓存中 singleFactories(key是besnName,value是FactoryBean)
      //singletonFactory是通过lamda表达式获取得到的
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      //赋值属性的,重要
      //主要借助Common和Autowired两个后置处理器来填充属性
      //bean初始化第二步:填充属性(DI依赖注入发生在此步骤)
      populateBean(beanName, mbd, instanceWrapper);
      /**
       * 重点,这里就是把原生对象变成代理对象的地方
       * bean初始化第三步:调用初始化方法,完成bean的初始化,aop发生在此步骤
       * 例如<besn init-method=""></besn>中的init-method方法就是在这里调用的
       */
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
 
   }   
   return exposedObject;
}

当创建完B类对象,也将B类对象存入到三级缓存singletonFactories中,填充B类对象属性时,发现依赖A类,接着同理调用populateBean => applyPropertyValues

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
   //遍历所有的属性进行填充,包括A类对象
   for (PropertyValue pv : original) {
      if (pv.isConverted()) {
         deepCopy.add(pv);
      }
      else {
         String propertyName = pv.getName();
         Object originalValue = pv.getValue();
         //循环依赖重点
         //!!!!重点
         //一位属性中的对象还没有创建,所以不能直接设置属性值,必须先创建属性对象
         Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
         
   // Set our (possibly massaged) deep copy.
   try {
      //重点
      //完成依赖注入
      bw.setPropertyValues(new MutablePropertyValues(deepCopy));
   }  
}

同理,通过resolveValueIfNecessary查找A类对象,最后通过setPropertyValues将A类对象填充到B类对象属性中,查看resolveValueIfNecessary,如下:

@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
   // We must check each value to see whether it requires a runtime reference
   // to another bean to be resolved.
   if (value instanceof RuntimeBeanReference) {
      RuntimeBeanReference ref = (RuntimeBeanReference) value;
      //重点看该方法
      return resolveReference(argName, ref);
   }   
}

同理查看resolveValueIfNecessary方法,如下:

@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
   try {
     
      if (ref.isToParent()) {
         
      }
      else {
         //重点!!!
         //从Spring容器中找属性对象
         //进去之后发现跟刚刚创建对象是一样的过程
         bean = this.beanFactory.getBean(refName);
         this.beanFactory.registerDependentBean(refName, this.beanName);
      }
      
}

接着getBean方法走上面同样的流程获取对象a,getBean => doGetBean

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

   //因为你的beanName有可能加了&,所以要将&移除
   //这里用到的是FactoryBean的知识
   final String beanName = transformedBeanName(name);
   Object bean;

   //从三级缓存中获取bean对象,面试重点 spring三级缓存
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
       
      //如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   //重点,容器中没有该对象的实例
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      /**
       * 如果是原型,不应该在初始化的时候创建
       * spring当中的标识CurrentlyInCreation标识该类正在创建
       */
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

         // Create bean instance.
         //重点重点
         if (mbd.isSingleton()) {
            /**
             * getSingleton相当于从缓存中根据beanName取出对象,
             * 如果取不到,就回调下面的匿名内部类的createBean方法
             */
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  //重点
                  //真正调用AbstractAutowireCapableBeanFactory中的createBean方法
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                   
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
      }
      catch (BeansException ex) {
         
      }
   }
    
   return (T) bean;
}

注意此时a对象已创建出来并存入到三级缓存中了,查看Object sharedInstance = getSingleton(beanName);,如下:

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //这个singletonObjects就是微观springioc容器
   //从一级缓存中获取单例对象
   Object singletonObject = this.singletonObjects.get(beanName);
   /**
    * isSingletonCurrentlyInCreation
    * 判断当前单理bean是否正在创建中,也就是已经创建了对象实例但是还没有完成属性赋值
    * 比如A的构造器依赖了B对象所以得先去创建B对象,或者A的populateBean过程中依赖了B对象,得先去创建B对象
    * 这是A就是处于创建中的状态
    */
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         //从二级缓存中获取单例bean
         singletonObject = this.earlySingletonObjects.get(beanName);
         //allowEarlyReference是否允许从singletonFactories中通过getObject查到对象
         if (singletonObject == null && allowEarlyReference) {
            //从三级缓存中获取单理bean
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               //从三级缓存移动代理二级缓存
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

此时会将a对象从三级缓存singletonFactory移到二级缓存earlySingletonObjects中,并返回a对象。回到上面B类对象填充属性那一步,填充完a对象属性之后,接着初始化完成对象的完整操作,回到创建b对象doGetBean那一步,继续查看

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

   //因为你的beanName有可能加了&,所以要将&移除
   //这里用到的是FactoryBean的知识
   final String beanName = transformedBeanName(name);
   Object bean;

   //从三级缓存中获取bean对象,面试重点 spring三级缓存
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         
      }
      //如果取出来的Bean实例是FactoryBean的Bean实例,则需要从FactoryBean实例中产生一个对象实例
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   //重点,容器中没有该对象的实例
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      /**
       * 如果是原型,不应该在初始化的时候创建
       * spring当中的标识CurrentlyInCreation标识该类正在创建
       */
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      
         // Create bean instance.
         //重点重点
         if (mbd.isSingleton()) {
            /**
             * getSingleton相当于从缓存中根据beanName取出对象,
             * 如果取不到,就回调下面的匿名内部类的createBean方法
             */
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  //重点
                  //真正调用AbstractAutowireCapableBeanFactory中的createBean方法
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }    
   return (T) bean;
}

查看第二个带lamda表达式的getSingleton方法如下:此时已经执行完lamda比表达式createBean方法,即下面的singletonObject = singletonFactory.getObject();这一行代码,最终执行addSingleton将对象b加入到一级缓存singletonObjects中。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
          
         //往正在创建的bean的标识的容器中添加该beanName
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            //这行代码是真正创建对象的,该对象已经是一个代理对象了,重点
            /**
             * 后置处理器就是再这里把原生的变成代理对象,去看匿名内部类中的createBean方法
             * 这里其实就是调用外面的lamda表达式中的createBean方法
             */
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
           
         }
         
        
         if (newSingleton) {
            //重点,三级缓存解决循环依赖问题
            //实例化完成对象,并且对象设只属性和完成初始化之后
            //及那个该对象放入到一级缓存中
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

B类对象创建完成,并且加入到一级缓存singletonObjects中,最终返回到A对象填充属性那一步,填充完属性之后,接着同理初始化,走完创建对象流程,也即doGetBean那一步,接着同理,也回到上面的singletonObject = singletonFactory.getObject();这一步,最后执行addSingleton将对象a加入到一级缓存中。

总结

image.png

image.png

Spring解决循环依赖依靠的是Bean的“中间态"这个概念,而这个中间态指的是已经实例化但还没初始化的状态……>半成品。实例化的过程又是通过构造器创建的,如果A还没创建好出来怎么可能提前曝光,所以构造器的循环依赖无法解决。

Spring为了解决单例的循环依赖问题,使用了三级缓存

  • 其中一级缓存为单例池〈 singletonObjects)
  • 二级缓存为提前曝光对象( earlySingletonObjects)
  • 三级缓存为提前曝光对象工厂( singletonFactories)。

假设A、B循环引用,实例化A的时候就将其放入三级缓存中,接着填充属性的时候,发现依赖了B,同样的流程也是实例化后放入三级缓存,接着去填充属性时又发现自己依赖A,这时候从缓存中查找到早期暴露的A,没有AOP代理的话,直接将A的原始对象注入B,完成B的初始化后,进行属性填充和初始化,这时候B完成后,就去完成剩下的A的步骤,如果有AOP代理,就进行AOP处理获取代理后的对象A,注入B,走剩下的流程。

总体步骤:

  • 1 调用doGetBean()方法,想要获取beanA,于是调用getSingleton()方法从缓存中查找beanA

  • 2 在getSingleton()方法中,从一级缓存中查找,没有,返回null

  • 3 doGetBean()方法中获取到的beanA为null,于是走对应的处理逻辑,调用getSingleton()的重载方法(参数为ObjectFactory的)

  • 4 在getSingleton()方法中,先将beanA_name添加到一个集合中,用于标记该bean正在创建中。然后回调匿名内部类的creatBean方法

  • 5 进入AbstractAutowireCapableBeanFactory#doCreateBean,先反射调用构造器创建出beanA的实例,然后判断。是否为单例、是否允许提前暴露引用(对于单例一般为true)、是否正在创建中〈即是否在第四步的集合中)。判断为true则将beanA添加到【三级缓存】中

  • 6 对beanA进行属性填充,此时检测到beanA依赖于beanB,于是开始查找beanB

  • 7 调用doGetBean()方法,和上面beanA的过程一样,到缓存中查找beanB,没有则创建,然后给beanB填充属性

  • 8 此时beanB依赖于beanA,调用getsingleton()获取beanA,依次从一级、二级、三级缓存中找,此时从三级缓存中获取到beanA的创建工厂,通过创建工厂获取到singletonObject,此时这个singletonObject指向的就是上面在doCreateBean()方法中实例化的beanA

  • 9 这样beanB就获取到了beanA的依赖,于是beanB顺利完成实例化,并将beanA从三级缓存移动到二级缓存中

  • 10 随后beanA继续他的属性填充工作,此时也获取到了beanB,beanA也随之完成了创建,回到getsingleton()方法中继续向下执行,将beanA从二级缓存移动到一级缓存中

image.png