关于后端:spring-50x源码学习系列八-实例化bean之使用构造方法创建bean自动装配与循环依赖

29次阅读

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

前言

  • 上篇博客 spring 5.0.x 源码学习系列七: 后置处理器 ConfigurationClassPostProcessor 之 BeanFactoryPostProcessor 身份次要介绍了 ConfigurationClassPostProcessorBeanFactoryPostProcessor身份。接下来,将进入 spring 最外围的 bean 实例化 过程。

一、解析构建 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

正文完
 0