美文网首页
spring 5.0.x源码学习系列八: 实例化bean之使用构

spring 5.0.x源码学习系列八: 实例化bean之使用构

作者: avengerEug | 来源:发表于2021-03-22 09:01 被阅读0次

    前言

    一、解析构建bean过程

    • 构建bean的过程太复杂,将根据我自己写的流程图来一一讲解

    1.1 流程图

    在这里插入图片描述

    1.2 流程图解析

    1.2.1 创建非抽象、单例、非懒加载的bean

    整个正常流程是遍历bean工厂存放beanName的list, 并根据beanName拿到对应的beanDefinition,只过滤掉非抽象单例非懒加载的beand进行创建

    1.2.2 判断当前创建bean的类型并作相应处理

    因为spring存在两种bean, 普通beanFactoryBean,spring在区分这两种bean的做法是beanName和beanType来双重校验的。假设获取的bean为FactoryBean,那么会在getBean之前在beanName前添加一个&符号

        if (isFactoryBean(beanName)) {
            // org.springframework.beans.factory.BeanFactory#FACTORY_BEAN_PREFIX
            // String FACTORY_BEAN_PREFIX = "&";
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            // 后面的逻辑省略
        }
    

    1.2.3 getBean <=> doGetBean获取bean的通用方法

    • 此方法是spring根据beanName获取bean的通用方法。在此方法中有两个地方需要注意:
    1. 内部会对传入的beanName做处理(将传入的beanName前面的&符号去掉并存入内部自己维护的一个变量中), 此时关于当前bean的名称会有两个变量存储,分别是name(方法传入的bean名称), beanName(处理过bean名称)
    2. 不管是从bean工厂的单例池中获取还是新建的bean, 最终都要走getObjectForBeanInstance方法来返回bean。这样做主要是为了处理获取的bean类型为FactoryBean的情况。
      具体规则可参考此链接:https://github.com/AvengerEug/spring/tree/develop/resourcecode-study#%E5%8D%81%E4%B8%80-%E8%8E%B7%E5%8F%96factorybean%E5%AE%9E%E4%BE%8B%E4%B8%8E%E5%AE%83%E7%BB%B4%E6%8A%A4%E7%9A%84bean%E5%AE%9E%E4%BE%8B%E8%A7%84%E5%88%99

    1.2.4 第一次getSingleon

    • 此方法很重要
    1. 正常逻辑(循环bean工厂挨个创建bean)进来, 这里获取的值肯定为null
    2. 在populateBean自动装配需要创建依赖bean时, 这里获取的可能为null也可能不为null. 只有在循环依赖和spring单例池存在bean的情况下, 获取的才不为null, 因为此方法会首先从单例池中获取bean, 若不存在再根据这个bean是否正在被创建从而到"特殊"(根据beanName到singletonFactories拿ObjectFactory, 并根据ObjectFactory获取bean。
      public Object getSingleton(String beanName)
      

    1.2.5 第二次调用getSingleton

    • 此方法只有在创建新的bean时才会用到,传入的ObjectFactory是当前类的createBean方法
      public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)
      

    1.2.6 getSingleton内部的beforeSingletonCreation方法

    • 标记bean正在被创建:此动作很重要, 主要是将beanName存放至DefaultSingletonBeanRegistry类的singletonsCurrentlyInCreation数据结构(Set<String>), 后续会根据这个依据来解决循环依赖的情况, 即上述1.2.4 第一次getSingleon中所说的获取不为null的情况
      protected void beforeSingletonCreation(String beanName) {
          if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
              throw new BeanCurrentlyInCreationException(beanName);
          }
      }
      

    1.2.7 调用传入的createBean方法<=>singletonFactory.getObject()

    • 内部会调用至doCreateBean方法

    1.2.8 doCreateBean方法

    • 内部会创建出来bean, 创建完后还会在此方法中进行自动装配populateBean

    1.2.9 createBeanInstance方法

    • 此方法为真正创建bean的流程,内部主要做了如下事情
    1. 确定当前bean是否通过构造方法自动装配, 源码和条件如下:

      Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
         if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
             return autowireConstructor(beanName, mbd, ctors, args);
         }
      
      1. ctors != null  => ctors中存的是构造方法中添加@Autowired注解的情形
      2. mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR  => 此条件为使用后置处理器手动修改beanDefinition的自动装配的值, 默认为no
      3. mbd.hasConstructorArgumentValues()
          => 使用后置处理器手动添加beanDefinition中存放构造方法值的情形,
           eg: mybatis中的definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
      4. !ObjectUtils.isEmpty(args)
      
      上述条件只要满足一个就走构造方法自动装配的逻辑
          ```
      
    2. 若使用构造方法自动装配的结论不成立则走默认构造方法创建bean流程

    3. 不管是默认构造方法创建bean还是通过构造方法自动装配bean,所有bean的创建使用的都是CglibSubclassingInstantiationStrategy策略

    1.2.10 确认当前bean是否符合循环依赖的情况 <=> addSingletonFactory方法

    • 满足循环依赖的三个条件: 单例、allowCircularReferences为true、当前的bean正在创建中
          protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
              Assert.notNull(singletonFactory, "Singleton factory must not be null");
              synchronized (this.singletonObjects) {
                  if (!this.singletonObjects.containsKey(beanName)) {
                      // 存放bean对应的ObjectFactory, 在bean的循环依赖中会用上
                      this.singletonFactories.put(beanName, singletonFactory);
                      this.earlySingletonObjects.remove(beanName);
                      // 存放已经被注册过的bean
                      this.registeredSingletons.add(beanName);
                  }
              }
          }
      
    • 使用构造方法创建bean后, 会做三个操作:
    1. this.singletonFactories.put(beanName, singletonFactory);
      => 在getBean方法的第一次getSingleton中会用到,其实这个singletonFactory的形参中已经在创建bean的过程中传入了,并且内部的逻辑是执行SmartInstantiationAwareBeanPostProcessor后置处理器的getEarlyBeanReference方法,此方法可以返回一个bean)的地方去拿bean

    2. this.earlySingletonObjects.remove(beanName);

    3. this.registeredSingletons.add(beanName); => 此步骤只是为了记录这个bean已经被spring创建了或者正在被创建中

      所以创建一个bean后(还未依赖注入bean), 会在singletonFactories和registeredSingletons数据结构中都存在相关记录

    1.2.11 自动装配 <=> populateBean方法

    • 此方法中主要是AutowiredAnnotationBeanPostProcessor后置处理器来实现自动装配,若bean需要自动装配,则还需要先实例化依赖的bean,最终又会走到上述getBean逻辑

    1.2.12 bean创建完毕, 开始执行bean的一些后置处理器

    1. 调用bean的BeanPostProcessor后置处理器postProcessBeforeInitialization方法
    2. 若bean实现了InitializingBean接口, 则调用接口中的方法afterPropertiesSet
    3. 调用bean的BeanPostProcessor后置处理器de postProcessAfterInitialization方法

    1.2.13 清除bean正在创建的标识并添加至bean工厂

    • afterSingletonCreation
        // this.singletonsCurrentlyInCreation.remove(beanName) => 移除当前bean name
        protected void afterSingletonCreation(String beanName) {
            if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
                throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
            }
        }
    
    • addSingleton
        protected void addSingleton(String beanName, Object singletonObject) {
            synchronized (this.singletonObjects) {
                // bean工厂单例池
                this.singletonObjects.put(beanName, singletonObject);
                // 执行到这表示当前bean已经创建完成, 则移除循环依赖的bean的情况, 
                // 若下次还有bean依赖它, 直接从bean工厂的单例池获取即可
                this.singletonFactories.remove(beanName);
    
                // 当前bean被创建完毕,则清除它
                this.earlySingletonObjects.remove(beanName);
    
                // 再次将bean添加至该集合中, 该集合是一个set, 不会重复, 这里重复添加的原因可能是并发情况
                this.registeredSingletons.add(beanName);
            }
        }
    

    二、一个案例搞清楚循环依赖

    2.1 案例背景

    • 有两个类: A和B,它们互相依赖(A中要自动装配B属性,B中要自动装配A属性), 假设先创建A

    2.2 流程

    1. 创建Bean a <=> getBean("a")
      第一次调用getSingleton方法, 单例池中无bean a ,也没标识正在被创建, 所以走第二个getSingleton方法。此时a被标注正在被创建走使用构造方法创建bean的逻辑
    2. 在创建完a后开始记录bean a的一些状态(将bean name添加至registeredSingletons以及将bean对应的ObjectFactory添加至singletonFactories。即上述的addSingletonFactory方法的操作)和填充属性, 发现它依赖于B, 此时要去getBean(b)
    3. 然后进入创建bean b流程 <=> getBean("b")
    4. 此时会进入第一个getSingleton方法, 此时spring单例池中无b并且b也还未被标注为被创建(因为它是在getSingleton方法后面标注的)状态所以进入创建createBean方法
    5. 同理, 在创建完b后也会记录bean b的一些状态(将bean name添加至registeredSingletons以及将bean对应的ObjectFactory添加至singletonFactories。即上述的addSingletonFactory方法的操作)
    6. 创建完b后开始填充属性, 发现它又依赖于A, 此时要去getBean("a")
    7. 此时进入第一个getSingleton方法, 发现单例池中无a(虽然a在上述过程中被创建了, 但是它还未放入单例池中)但是它是处于被创建的状态, 所以从singletonFactories中根据beanName拿ObjectFactory, 最终从ObjectFactory拿到Bean a, 并将singletonFactories中beanName对应的objectFactory remove掉,以及将拿到的bean a放入到earlySingletonObjects中
    8. 最终拿到了bean a, 此时将bean a注入到bean b中的a属性中, 完成bean b的创建(此时会将它正在创建的标识移除并它放入单例池中去), 并调用BeanPostProcessor后置处理器以及InitializingBean接口的afterPropertiesSet方法, 至此bean b的创建结束了 返回bean b。
    9. 因为上述创建bean b的过程是a要自动装配b而执行的, 为的就是获取bean b。现在已经拿到bean b了, 所以将bean a中的b属性给注入进去, 最终完成bean a的创建, 将a也添加到spring单例池中并调用BeanPostProcessor后置处理器以及InitializingBean接口的afterPropertiesSet方法
    10. bean a创建完成,循环依赖步骤完成
    • 涉及到的几个数据结构:
      1. registeredSingletons: 表示该bean已经通过构造方法创建出来了
      2. singletonFactories: 存放bean对应的objectFactory方法, 循环依赖时需要根据它来拿bean
      3. earlySingletonObjects: 与singletonFactories的操作是互斥的, 里面存放的是singletonFactories中beanName对应的objectFactory创建出来的bean,若一个beanName在该集合中存在, 那么该bean对应的ObjectFactory就会在singletonFactories中被remove掉
      4. singletonsCurrentlyInCreation: 表示当前bean正在被创建, 在getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法中进行操作, 添加、移除正在创建的标识都是在此方法中完成

    三、spring bean实例化过程中涉及到的后置处理器和执行顺序

    执行顺序 执行位置 执行到的后置处理器 执行的方法 作用
    1 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.doCreateBean
    => resolveBeforeInstantiation方法
    InstantiationAwareBeanPostProcessor 1. postProcessBeforeInstantiation
    2.postProcessAfterInitialization
    1. postProcessBeforeInstantiation作用:
    若后置处理器中返回了一个对象, 则不会走spring的创建bean的流程
    2.若postProcessBeforeInstantiation方法返回的bean不为null则执行postProcessAfterInitialization方法,该方法执行了BeanPostProcessor后置处理器, 自动装配的后置处理器就间接实现了BeanPostProcessor, 若BeanPostProcessor不被执行, 那么自动装配的功能也将缺失
    3. 若bean中实现了aware接口,那么将按照aware的类型诶个执行对应的方法,其中就包括获取spring上下文的ApplicationContextAware
    2 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.createBeanInstance
    => determineConstructorsFromBeanPostProcessors
    SmartInstantiationAwareBeanPostProcessor determineCandidateConstructors 扫描当前bean携带@Autowired注解的构造方法或者只有一个带参的构造方法或者等等其他的情况。(具体参考AutowiredAnnotationBeanPostProcessor类的determineCandidateConstructors方法)
    3 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.doCreateBean
    => applyMergedBeanDefinitionPostProcessors
    MergedBeanDefinitionPostProcessor postProcessMergedBeanDefinition 将当前类需要自动装配的属性全部InjectionMetadata对象中(每个属性对应一个InjectionMetadata对象)
    4 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.doCreateBean
    => getEarlyBeanReference
    SmartInstantiationAwareBeanPostProcessor getEarlyBeanReference 当处理循环依赖时,会获取到状态为'正在创建'的bean的引用
    5 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.populateBean
    => postProcessAfterInstantiation
    InstantiationAwareBeanPostProcessor postProcessAfterInstantiation 能够控制当前bean是否继续完成依赖注入逻辑,若方法return false,则当前bean的@Autowired注解功能的依赖注入结束
    6 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.populateBean
    => postProcessPropertyValues
    InstantiationAwareBeanPostProcessor postProcessPropertyValues 处理当前bean自动装配的属性
    7 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.initializeBean => applyBeanPostProcessorsBeforeInitialization
    BeanPostProcessor postProcessBeforeInitialization 当bean被实例化并完成自动装配之后执行
    8 org.springframework.beans.factory.support.
    AbstractAutowireCapableBeanFactory.initializeBean
    => applyBeanPostProcessorsAfterInitialization
    BeanPostProcessor postProcessAfterInitialization 当bean被实例化并完成自动装配之后执行,比postProcessBeforeInitialization方法后执行
    • 如上, 一共会执行4个后置处理器InstantiationAwareBeanPostProcessor, SmartInstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, BeanPostProcessor, 共执行了8次, 其中InstantiationAwareBeanPostProcessor类型的后置处理器调用次数最多, 8次调用中有5次跟它有关, 因为它继承了BeanPostProcessor, 并扩展了三个方法postProcessBeforeInstantiation、 postProcessAfterInstantiation和postProcessPropertyValues

    四、小结

    • 本篇博客还有很多细节未提及,比如spring如何知道使用哪一个构造方法(假设程序员提供了多个构造器)创建bean、自动装配后置处理器AutowiredAnnotationBeanPostProcessor是如何知道哪些属性需要装配哪些不需要、在5个后置处理器的八个地方被调用的具体作用和景点案例也未完全总结等等。只能等日后再完善了
    • I am a slow walker, but I never walk backwards.
    • github spring源码学习地址: https://github.com/AvengerEug/spring/tree/develop/resourcecode-study

    相关文章

      网友评论

          本文标题:spring 5.0.x源码学习系列八: 实例化bean之使用构

          本文链接:https://www.haomeiwen.com/subject/imaacltx.html