Spring 获取单例流程(三)

简介: 读完这篇文章你将会收获到• Spring 何时将 bean 加入到第三级缓存和第一级缓存中• Spring 何时回调各种 Aware 接口、BeanPostProcessor 、InitializingBean 等

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

  • 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 是一个单例,

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 是通过这种方式注入的话(autowireByNameautowireByType )、就是在这一步注入的了,他获取其他 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 给调用方





目录
相关文章
|
2月前
|
XML 前端开发 Java
深入了解Spring MVC工作流程
深入了解Spring MVC工作流程
|
1天前
|
Java Spring 容器
深入理解Spring Boot启动流程及其实战应用
【4月更文挑战第9天】本文详细解析了Spring Boot启动流程的概念和关键步骤,并结合实战示例,展示了如何在实际开发中运用这些知识。
9 2
|
2月前
|
安全 Java Spring
Spring 的 Controller 是单例还是多例?怎么保证并发的安全
Spring 的 Controller 是单例还是多例?怎么保证并发的安全
19 0
|
2月前
|
安全 Java Spring
Spring 的 Controller 是单例还是多例?怎么保证并发的安全
Spring 的 Controller 是单例还是多例?怎么保证并发的安全
13 0
|
2月前
|
JSON Java 数据库连接
【spring(五)】SpringMvc总结 SSM整合流程
【spring(五)】SpringMvc总结 SSM整合流程
|
2月前
|
Java Spring 容器
【Spring源码】单例创建期间进行同步可能会导致死锁?
通过这个标题我们就可以思考本次的阅读线索了,看起来可以学到不少东西。1. 旧代码的死锁是怎么产生的。2. 贡献者通过改变什么来解决本次PR的问题呢?而阅读线索2的答案也显而易见,就是上文提到的通过后台线程来创建Micrometer单例...
47 3
|
3月前
|
缓存 Java uml
SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
46 0
|
4月前
|
前端开发 Java Spring
一文讲述Spring MVC的执行流程
一文讲述Spring MVC的执行流程
46 0
|
4月前
|
安全 Java 数据安全/隐私保护
Spring Security OAuth 认证流程浅析:授权码模式
【1月更文挑战第16天】上一篇[Spring Security OAuth 认证流程浅析:密码模式],简单分析了密码模式授权流程的源码,这篇来试着分析 OAuth 中最具代表性的授权码模式。
78 4
|
4月前
|
安全 Java 数据安全/隐私保护
Spring Security OAuth 认证流程浅析:密码模式
【1月更文挑战第15天】从 Spring Security OAuth 源码分析其实现原理。这篇我们先分析最常用也相对简单的密码模式。
87 0