Spring循环依赖

 2023-02-08
原文作者:goAhead 原文地址:https://juejin.cn/post/7011850089949823006

概念

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

202301012122465051.png

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

202301012122473372.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 方法判断该对象是否在创建中,什么叫做创建中?即已经实例化了对象,但是还没有给都对象进行属性赋值。如果在创建中,则查看二级缓存中是否有该对象,如果没有接着查看三级缓存。
    1. 实例化对象之后,在进行属性赋值之前,即调用 populateBean 之前,会调用 addSingletonFactory 方法将对象实例放入到Spring三级缓存 singletonFactories 中,然后后面进行属性赋值以及初始化,
    1. 对象实例化,属性赋值以及初始化完成之后调用 addSingleton 方法将该对象放入到一级缓存 singletonObjects 中。

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

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

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

202301012122483483.png

源码分析

202301012122492904.png

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

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

202301012122518577.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方法创建对象,如下:

202301012122529248.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方法,如下:

202301012122539939.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加入到一级缓存中。

总结

2023010121225466610.png

2023010121225554111.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从二级缓存移动到一级缓存中

2023010121225693812.png