Spring-获取单例流程三

6次阅读

共计 5678 个字符,预计需要花费 15 分钟才能阅读完成。

读完这篇文章你将会收获到

  • Spring 何时将 bean 加入到第三级缓存和第一级缓存中
  • Spring 何时回调各种 Aware 接口、BeanPostProcessorInitializingBean

相关文章

  • Spring 获取单例流程(一)
  • Spring 获取单例流程(二)
  • Spring 循环依赖 (公众号内查看(同时发布无法获取到链接))

概述

上两篇文章 Spring 获取单例流程(一) 和 Spring 获取单例流程(二) 介绍了 getBean 前面的流程,今天最后的收尾,把后面的流程继续一起学习下

源码分析

// 我依赖的大哥都好了
// Create bean instance.
if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {
      try {return createBean(beanName, mbd, args);
      } catch (BeansException ex) {
         // 从三级缓存中移除这个 beanName  因为它可能被放进去了 因为放进去三级缓存可以解决 setter 的循环依赖
         destroySingleton(beanName);
         throw ex;
      }
   });

   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} 

如果我们要创建的 bean 是一个单例,

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {
      // 看看第一级缓存中有没有
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {

         // 将 beanName 加入到 singletonsCurrentlyInCreation 中,代表它正在创建中
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;

         try {singletonObject = singletonFactory.getObject();
            newSingleton = true;
         } catch (IllegalStateException ex) {throw ex;} catch (BeanCreationException ex) {throw ex;} finally {
            // singletonsCurrentlyInCreation 从这里面移除掉
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            // 加入缓存中
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

删减了部分不重要的代码,我们大致来看看其流程

  1. 获取同步锁,然后判断 第一级缓存 是否已经存在这个 bean
  2. 如果不存在则将 beanName 加入到 singletonsCurrentlyInCreation 中,代表它正在创建中
  3. 然后调用参数的 ObjectFactorygetObject 方法获得一个 bean
  4. 最后将其从 singletonsCurrentlyInCreation 中移除、代表其已经创建完成了
  5. 最后将其加入到 第一级缓存 中、从 第二级和第三级缓存 中移除掉

全篇完结. 终 !!!

其实真正的秘密藏身在参数的 ObjectFactory 中,从上面的流程中可以宏观的知道 Spring 创建 bean 的一个流程

现在我们在看看参数的 ObjectFactory 究竟干啥子了

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

   ...........
   ...........

   try {
      // 真正 处理逻辑
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean'" + beanName + "'");
      }
      return beanInstance;
   } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {throw ex;} catch (Throwable ex) {throw new BeanCreationException(xxxx);
   }
}

干活的还是 do 开头的大佬

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

   // Instantiate the bean.
   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();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   
  ..........
  .........
   // 是否需要提前曝光、用来解决循环依赖的问题
   // 是单例 & 允许循环依赖 & 正在创建中
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
         isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
      // 为了避免后期循环依赖、可以在 bean 初始化前将创建实例的 ObjectFactory 加入工厂
      addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
      // 填充属性
      populateBean(beanName, mbd, instanceWrapper);
      // 调用初始方法
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   } catch (Throwable ex) {.........}

   ........
   .......
  

   return exposedObject;
}

上面的流程大致就是

  • createBeanInstance 这个方法根据你的配置以及你的 bean 的情况选择出一种创建 bean 的方法、可能是工厂方法、可能是某个构造函数、可能是默认的构造函数。这里包含了当一个构造函数的参数是另一个 bean 的时候、它会通过 getBean 的方法获取这个参数的 bean
  • 然后将创建好的 bean 加入到 第三级缓存 中,默认设置我们是允许循环依赖的
  • populateBean 方法就是我们填充属性了、如果你依赖的其他 Spring 的其他 bean 是通过这种方式注入的话 (autowireByName autowireByType )、就是在这一步注入的了,他获取其他 bean 也是通过 getBean 的方式获取

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        .........
        .........
      
          if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);
          }
          // Add property values based on autowire by type if applicable.
          if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);
          }
        .........
        .........
    }
  • initializeBean 则是调用我们的各种回调接口、Aware 类型的、BeanPostProcessorInitializingBean、自定义初始化函数

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {。// 调用各种 Aware 接口
             invokeAwareMethods(beanName, bean);
             return null;
          }, getAccessControlContext());
       } else {
           // 调用各种 Aware 接口
          invokeAwareMethods(beanName, bean);
       }
    
       Object wrappedBean = bean;
       if (mbd == null || !mbd.isSynthetic()) {
           // 调用 BeanPostProcessor postProcessBeforeInitialization
          wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
       }
    
       try {
           // 调用 InitializingBean、自定义的初始化方法
          invokeInitMethods(beanName, wrappedBean, mbd);
       } catch (Throwable ex) {
          throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
       }
       if (mbd == null || !mbd.isSynthetic()) {
           //  调用 BeanPostProcessor postProcessAfterInitialization
          wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
       }
       return wrappedBean;
    }

    其实整体的流程就差不多了

总结

  • 根据参数中的 name 找出对应的 beanName、无论这个 name 是别名或者是一个 factoryBeanbeanName
  • 查看缓存中是否包含这个 beanName 对象

    • 先从一级缓存 singletonObjects 中看看有没有
    • 然后从二级缓存 earlySingletonObjects
    • 都没有的话再从三级缓存 singletonFactories 中看看有没有
  • 如果缓存中有 bean、那么我们还是需要处理一下这个 bean

    • 如果 Spring 缓存中返回的 beanfactoryBean、而用户也想要的是一个 beanFactory (参数 name 中的前缀是 & )、那么我们直接返回
    • 如果 Spring 缓存中返回的 bean 是普通的 bean、而用户也想要的是一个普通的 bean、那么就直接返回
    • 如果 Spring 缓存中返回的 bean 是一个 factoryBean、而用户想要的是一个普通的 bean、那么我们就要从 factoryBean 中获取这个 bean
    • 而从 factoryBean 中获取这个 bean 的过程中、需要调用到前置处理、后置处理和我们常用的接口回调 BeanPostProcessor
  • 如果缓存中没有 bean、则判断是否是 prototype 类型并且循环依赖
  • 如果没有则尝试能否在父容器中找到该 bean
  • 如果父容器也没有则获取该 beanName 对应的 beanDefinition 找出其依赖的 beanName
  • 判断该 beanName 与 依赖的 beanName 是否循环依赖、没有则注册其依赖关系并调用 getBean 方法去创建依赖的 beanName
  • beanName 加入到 singletonsCurrentlyInCreation
  • 根据指定 bean 使用对应的策略创建新的实例、如工厂方法、构造函数、创建一个不完整的 bean
  • 将创建好的 bean 加入到 第三级缓存
  • 进行属性填充、进行各种接口回调
  • 最后将其从 singletonsCurrentlyInCreation 中移除、代表其已经创建完成了
  • 最后将其加入到 第一级缓存 中、从 第二级和第三级缓存 中移除掉
  • 返回 bean 给调用方

其实总体的流程还是不算复杂把、我们也可以从中收获到一些东西。其实我们最关心也是面试最常问的一个问题就是、Spring 如何解决循环依赖的问题、感兴趣的可以看看这篇文章公众号内的 Spring 循环依赖 这篇文章

正文完
 0