zoukankan      html  css  js  c++  java
  • 【spring源码分析】一、spring Refresh流程

    1.初始化AnnotatedBeanDefinitionReader

    • 主要用于把spring内置的6种beanFactoryPostProcess注册到容器中
    • 提供给程序员注册bd,主要是加了@Configuration的类。

    2.初始化ClassPathBeanDefinitionScanner

    • 程序员在外部可以调用,用于bd的扫描
    • spring内部不是用它,而是自己重新new scanner来扫描

    3.执行register,把我们自己的配置类注册到spring容器

    4.执行refresh(),spring生命周期主要的功能都是在这里实现,下述步骤为详解

    5.执行invokeBeanFactoryPostProcessors,完成bean的扫描、解析、PostBeanProcessors和BeanFactoryPostProcessors的执行等

    • 先执行beanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法

      • 先执行外部通过context.add进来的BeanDefinitionRegistryPostProcessor
      • 再执行spring内部的BeanDefinitionRegistryPostProcessor,正常情况这里只有ConfigurationClassPostProcessor,为初始化AnnotatedBeanDefinitionReader的时候注册进的spring,扫描、解析、校验,初始化bd等
      • 接着执行程序员通过注解注册的 并且特殊的比如 实现了PriorityOrdered,Order的BeanDefinitionRegistryPostProcessor
      • 最后执行其他普通的BeanDefinitionRegistryPostProcessor
    • 再执行直接实现了beanFactoryPostProcessor类的postProcessBeanFactory方法

      • 执行实现了BeanFactoryProcessor的子类BeanDefinitionRegistryPostProcessor的postProcessBeanFactory
        • 先执行外部通过context.add进来的BeanDefinitionRegistryPostProcessor
        • 再执行接着执行程序员通过注解注册的BeanDefinitionRegistryPostProcessor
      • 再执行外部通过context.add进来的beanFactoryPostProcessor
      • 接着执行程序员通过注解注册的 并且特殊的比如 实现了PriorityOrdered,Order的beanFactoryPostProcessor
      • 最后执行其他普通的beanFactoryPostProcessor

    6.上述ConfigurationClassPostProcessor把将类变成bd的详解

    • 从BeanDefinitionRegistry中获取所有的bd,取出bd不是full或者lite,并且是Configuration类的bd(check的时候会给class添加full或者lite,纯configuration为full,Component、ComponentScan、Import、ImportResource为lite)

    • 遍历解析配置类

      • 先处理配置类的内部类

      • 处理@PropertrySource 环境配置

      • 处理@ComponentScan,会调用ClassPathBeanDefinitionScanner,根据包路径,和匹配规则扫描出合格类,放到map中

      • 处理@Import

        a.先处理 ImportSelect,执行selectImports(),

        b.然后处理 ImportBeanDefinitionRegistrar接口,会放到该bd的一个Map中,循环map统一去执行实现方法registerBeanDefinitions

        c.最后处理普通的类,同样会递归去解析该bd。aop

      • 处理@ImportResource

      • 处理@Bean

      • 处理接口bd

    • 将所有的合格的类,转换成bd,注册到beanDefinitionRegistry。

    7.注册beanPostProcessor后置处理器,国际化等等

    8.finishBeanFactoryInitialization真正实现实例化bean(单例非懒加载),getbd,把bd变成springbean,遍历map,各种验证,都验证通过,这里有两次getSingleton

    9.先合并bd,getMergedLocalBeanDefinition,进行一些简单的验证

    关于循环依赖的一些重要类

    singletonObjects 一级缓存,完整的bean

    singletonFactories 二级缓存,存的是代理bean工厂

    earlySingletonObjects 三级缓存,一般是是半成品的bean

    isSingletonCurrentlyInCreation 就是一个set集合,存放正在执行中的beanName

    注:这里的一级缓存和三级缓存没有明确的定义

    10.第一次getSingleton,一般单例池中是不存在的,并且不是正在创建bean的set集合中isSingletonCurrentlyInCreation(在多线程、循环依赖的情况下,单例池中不为null)

    • 存在,直接拿出来
    • 不存在,并且不在isSingletonCurrentlyInCreation中,返回null
    • 不存在,在isSingletonCurrentlyInCreation中,从三级缓存中中拿
      • 三级缓存中存在,直接拿
      • 三级缓存中不存在,通过二级工厂拿代理bean工厂,获得该bean,然后将得到bean放到三级缓存中,移除二级缓存(留一个问题,这里的二级工厂是怎么会有该工厂bean的,isSingletonCurrentlyInCreation里又是什么时候会有beanName的)

    11.第一次getSingleton如果没取到,又是一系列是否存在正在创建当原型集合当中,是否有父子容器验证等等校验一切校验通过,执行第二次getSingleton,先判断一级缓存是否存在

    • 存在,直接拿出来
    • 不存在
      • 首先将beanName放到正在创建bean的set集合中,表示正在创建该bean,判断是不是在在排除对象中
      • lambda延迟机制,就会调用表达式中,也就是createBean,这时候是正在获取代理bean工厂会走一个完整的bean 的生命周期
      • 根据注入模型推断构造方法创建对象
      • 如果是单例的,正在创建的bean,且此时单例池中没有,把工厂对象存到二级缓存中,删除三级缓存

    12.完成属性注入

    13.执行生命周期各种回调以及aop等

    eg:class A 和ClassB相互引用

    1)a先执行第一次getSingleton,一级缓存中无,并且没有在正在创建的bean名单中,一系列校验后

    2)执行第二次getSingleton,此时一级缓存中还是无,这个时候把nameA放到正在创建的bean集合中,推断a的构造方法,去创建a对象,把工厂对象a放到二级缓存中,执行a的属性注入,此刻发现a中有注入b,spring容器中还没有b,这个时候去doGetBean b

    3)b第一次getSingleton,一级缓存中无,并且b没有在正在创建的bean名单中,一系列校验后

    4)执行b的第二次getSingleton,此时一级缓存中还是无,这个时候把nameb放到正在创建的bean集合中,推断b的构造方法,去创建b对象,把工厂对象b放到二级缓存中,执行b的属性注入,此刻发现b中有注入a,spring容器中还没有a,这个时候去doGetBean a

    5)a再一次执行第一次getSingleton,一级缓存中无,由2)得知此刻a在正在创建的bean名单中,并且二级缓存中存在a,去看三级缓存中是否存在,显然,现在是不存在的,通过二级工厂拿代理beanA工厂,获得该beanA,然后将得到beanA放到三级缓存中,移除二级缓存A,返回半成品的beanA(生命周期还没有走完 ),继续第4)步b接下来的生命周期过程,注入其他属性,执行b的生命周期各种回调以及aop等,完成b的整个生命周期

    6)执行2)a的接下来生命周期,此时a中注入的b已经是一个完整的bean,执行a的生命周期各种回调以及aop等,完成a的整个生命周期,因为b中注入的是a的引用,此时,b中的a也就被填充完整,这样,一个完整是循环依赖流程走完

  • 相关阅读:
    第二阶段~JS中的各种循环语句
    项目一~达人美食图册详情
    项目一~达人行程
    项目一~美食达人图册
    项目一~机票2
    项目一~达人首页
    项目一~Hotel5
    pythonday02基础与运算符
    pythonday01计算机初步认识
    第六章 百度Apollo ROS介绍(2)
  • 原文地址:https://www.cnblogs.com/faramita/p/14603021.html
Copyright © 2011-2022 走看看