Spring 获取单例流程(三)

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

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

相关文章面试

概述

上两篇文章 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 是一个单例,app

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 究竟干啥子了post

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; } 复制代码

上面的流程大体就是this

  • 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 循环依赖 这篇文章

此次必定?
此次必定?
群聊
群聊
相关文章
相关标签/搜索