• springioc源码


    spring-ioc源码

    需要解决的问题
    1. beanfactory和factorybean的区别
    2. beanfactorypostprocessor在spring中的作用
    3. springioc的加载过程
    4. bean的生命周期
    5. spring中有哪些扩展接口及调用时机

    大纲

    1. 主要流程-springioc的加载过程
    1. 实例化容器AnnotationConfigApplicationContext
    2. 实例化工厂DefaultListAbleBeanFactory
    3. 实例化建立beanDefination读取器 annotatedBeandefinationReader
    4. 创建beandefination扫描器:classPathBeanDefiantionScanner
    5. 注册配置类为beanDefination: register方法,annotatedClasses
    6. refresh
    7. invokeBeanfacorypostProcessors(beanfactory)
    8. finishBeanfactoryinitialization(beanfactory)
    2. 主要流程-spring bean的生命周期

    springioc的加载过程

    1. 首先准备个例子如下(插入图片)

      1. mainconfig,负责注册

      2. car.java 普通的bean

      3. mainstart 负责加载spring上下文创建bean

      2.springioc的容器加载流程

      1. 实例化容器从annotationConfigApplicationContext开始
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
      

      annotationConfigApplicationContext的关系图如下

      1645688548880

      创建annotationConfigApplicationContext对象

      1645688658208

      首先看这个构造方法

      1. 这是一个有参构造方法,可以接受多个配置类,不过一般情况只传入一个配置类。

      2. 这个配置类有俩种情况,一种是传统意义上的带@Configutarion注解的配置类,还有一种是带@Component,@import,@importResource等注解的配置类,在spring中前者被称为full配置类,后者叫lite配置类,也叫普通bean

        查看这个this()方法都干了什么,如图

        1645688903623

        1645688921967

        首先无参构造方法中就是对读取器read和扫描器进行了实例化,reader的类型是annotatedbeandefinitionReader,可以看出他是一个 bean定义读取器,scanner的类型是classpathbeandefinitionscanner,它仅仅是外面手动调用.scan方法,

      3. 实例化工厂:defaultListableBeanFactory

        1645689641110

        DefaultListableBeanFactory的关系图

        1645689741004

        defaultlistablebeanfactory是bean的工厂,是用来生产和获得bean。

      4. 实例化建beanDefinition读取器:annotatedbeandefinitionReader

        主要负责俩件事

        1. 注册内置beanPostprocrssor

          1. 注册相关的beandefinition

        1645689973664

        ​ 回到annotationconfigapplicationcontext的无参构造方法,看annotatedbeandefinitionreader

        1645690106882

        这里beandefinitionregistry是annotationconfigapplicationcontext的实例,这里调用其他类构造方法

        1645690190247

        1645690254788

        1645690275071

        这个方法就是注册spring的内置的多个bean

        1. 判断容器内是否存在configurationclasspostprocessor bean

          1. 如果不存在,就通过rootBeanDefinition的构造方法获得configurationclasspostprocessor的beandefinition,rootbeandefinition是beandefinition的子类
          2. 执行registerpostprocessor方法,注册bean

        5 beandefinition是什么?

        1645692391007

        1. beanmetadataelement接口,beandefinition元数据,返回该bean的来源

        2. attributeaccessor接口,提供对beandefinition属性操作能力

          1645692476915

        3. 他是用来描述bean,里面存放着关于bean的一些列信息,比如bean的作用域,bean所对应的class,是否懒加载,是否primary等等。

        4. registerpostprocessor

          1645693385049

          这方法为beandefinition设置了role,ROLE_INFRASTRUCTURE代表这是spring内部的,并非用户定义的。然后又调用了registerBeandefinition方法,他的实现类是defaultlistablebeanfactory:

          1645693721324

          1645693731837

          从这里可以看出defaultlistablebeanfactory就是我们所说的容器,里面放着beandefinitionmap,beandifinitionnames,前者呢beanname做key,beandefinition做value,后者是个集合,里面放beanname。

          1645694111668

          ConfigurationClassPostProcessor实现了beandefinitionregistrypostprocessor接口,beandefinitionregistryPostProcessor又扩展了beanfactorypostprocessor接口,beanfactorypostprocessor是spring的扩展点之一,configurationclasspostprocessor是spring的重要类

          1645694839300

          除了注册configurationclass后置处理器还注册了其他bean,比如bean后置处理器,也是spring的扩展点之一。至此,实例化annotatedbeandefinitionreader reader完毕。

      5. 创建beandefinition扫描器,classpathbeandefinitionscanner

        1. 由于常规方法不会用到annotationconfigapplicationcontext里的scanner。这里的canner仅仅是为了程序员手动调用里面的scan方法
      6. 注册配置类为beandefinition: register(annotatedclasses)

        1645695523606

          1.  传入的参数是数组
        

        1645695562574

        1645695787967

        1645695805686

        这里需要注意的是以常规的方式去注册配置类,此方法除了第一个参数,其他参数都是默认值。

        1. 通过annotatedGenericBeanDefinition的构造方法,获取配置的bean定义,在注册configutationClass后置处理器也是通过构造方法获取bean定义,只是通过rootbeandefinition,现在是annotatedGenericBeanDefinition中获得
        2. 判断需不需要跳过注册,spring中有一个@Condition,如果不满足条件就会跳过这个类注册
        3. 解析作用域,如果没设置就默认为单例
        4. 获取beanname
        5. 解析通用注解,填充到annotatedGenericBeanDefinition,解析的注解为lazy,primary,dependsOn,role,Description
        6. 限定符处理,除了@Qualifier,还有primary,lazy
        7. 把annotatedGenericBeanDefinition数据结构和beanname封装到一个对象中
        8. 注册,最终会调用defaultlistableBeanFactory中的registerBeanDefinition方法注册

        1645760043965

        1645760131811

        1645760181568

      7. refresh()方法

        1645760271960

        1645760313824

        1645760327325

        1. prepareRefresh

          主要是做一些刷新前的准备工作,和主流程关系不大,主要是保存容器的启动时间,启动标志

        2. configurablelistablebeanfactory beanfactory = obtainFreshBeanFactory()

          和主流程关系不大,主要是把beanfactory取出来,xml模式下到这里会读取beanDefinition

        3. prepareBeanFactory

          添加了俩个后置处理器 applicationContextAwareProcessor,applicationListenerDetector,还设置了忽略自动装配 和允许自动装配的接口,如果不存在某个bean的时候,spring就自动注册singleton Bean.以及bean表达式解析器

          1645772418116

          1645772600210

          1645772631915

          主要的操作如下

          1. 设置了类加载器
          2. 设置了bean表达式解析器
          3. 添加了属性编辑器的支持
          4. 添加了一个后置处理器:applicationContextAwareProcessor,此后置处理器实现了beanpostprocessor接口
          5. 设置了一些忽略自动装配的接口
          6. 设置了一些允许自动装配的接口,并且进行了复制操作
          7. 在容器中还没有xxbean的时候,帮我们注册beanName为xx的单例bean
        4. postProcessBeanFactory(beanFactory)

          空方法,以后可能会被扩展

        5. invokeBeanFactoryPostProcessors(BeanFactory)

          1645774009646

          看这个小方法

          1645774279392

          这里获得的是beanFactorypostprocessor,可以手动添加一个后置处理器,而不是交给spring去扫描

          1645774492273

          只有这样,这个集合才不会为空。

          1645774569263

          1645774591021

          1645774609647

          1645774650601

          1645774680839

          1645774705464

          1645774731792

          1645774753470

          1645774773258

          1645774783913

          首先判断beanFactory是不是beandefinitionRegistry的实例,然后执行一下操作

          1. 定义一个set,装beanName,然后根据这个set,来判断后置处理器是否被执行过

          2. 定义俩个list,一个是regular后置处理器,用来装beanFactory后置处理器,一个是registryProcessors用来装载beanDefinitionRegistry后置处理器,其中bean定义注册后置处理器扩展了beanFactory后置处理器,bean定义注册后置处理器有俩个方法,一个是独有的后置处理器bean定义注册方法,一个是父类的后置处理器beanFactory方法

          3. 循环传入的beanfactory后置处理器,一般情况下都是空的,唯有手动加入beanFactory后置处理器。才有数据。因为bean定义注册后置处理器扩展了beanFactory后置处理器,所以这里要判断是不是bean定义注册后置处理器,是的话就执行后置处理器bean定义注册方法,然后把对象封装到registryprocessory中,不是的话就封装到regular后置处理器中

          4. 定义一个临时变量currentRegistryprocessors,用来装bean定义注册后置处理器

          5. getBeanNamesforType,通过类型找到beannames,从beanDefinitionNames去找,举个例子,如果这里传入了beanDefinitionregistryPostProcessor.class,就会找到类型为该类型的后置处理器。并且赋值给postProcessoryNames.一般情况下只会找到一个,就是internalconfigurationAnnotationProcessor,也就是confurationAnnotationProcess.如果你实现了bean定义后置处理器接口,也打上了@Component注解,但是在这里没有获取到,因为spring扫描实在configurationClass后置处理器类中完成的,也就是下面的invokeBeanDefinitionRegistry后置处理器方法。

          6. 循环postProcessorNames,是internalConfigurationAnnotationProcessor,判断此后置处理器是否实现了priorityordered接口。如果实现了,就把它添加到currentregistryProcessors中。再放入processedBeans,代表这个后置处理器已经被处理过了。

            1646017174949

          7. 进行排序,priorityOrdered是一个排序接口,如果实现了它说明后置处理器是有顺序的,要排序,目前只有configurationClass后置处理器

          8. 把currentRegistyprocessors合并到registryprocessors,因为一开始spirng只会执行beanDefinitionRegistry后置处理器的独有方法,而不执行父类方法,所以需要把这些后置处理器放入到一个集合中,后续统一执行beanFactoryProcessor接口中的方法。

          9. 可以理解为执行currentRegistryprocessors中的中的ConfigurationClass后置处理器中的postProcessBeanDefinitionRegistry方法,这里体现了spring的设计思想,热插拔。spring很多东西交给插件去做,如果不想用,就不添加

            1646018483587

          10. 清空currentRegistryProcessors,因为currentRegistryProcessors是一个临时变量,完成了目前的任务,所以清空,后面还会用到

          11. 再次根据bean定义注册后置处理器获得beanname,然后进行循环,看这个后置处理器是否被执行过了,如果没有执行,也实现了order接口,就把此后置处理器推送到currentRegistryprocessors和processedBean中。这里就可以获得我们定义的并且搭上了@Component注解的后置处理器。因为spring完成了扫描,但是需要注意由于ConfigurationClassPostProcessors上面已经被执行了,虽然可以通过getBeanNameForType获得,但是并不会加入到currentRegistryProcessors和processedBeanas.

          12. 处理排序

          13. 合并processors,合并的理由和上面一样

          14. 执行我们自定义的beandefinitionregistry后置处理器

          15. 临时清空变量

          16. 在上面的方法中,仅仅是执行了实现orderer接口的bean定义注册后置处理器,这里是执行没有实现ordered接口的bean定义注册后置处理器。

          17. 上面的代码时执行子类独有的方法,这里需要把父类的方法也执行一次

          18. 执行regular后置处理器中的后置处理器方法,需要注意的时,在一帮情况下,regular后置处理器,只有在外面手动添加beanFactory后置处理器才有数据。

          19. 查找实现了beanFactory后置处理器,并且执行了后置处理器中的方法。如下图

            1646038917775

            1646038943824

            1646039074503

            1646039116451

            1646039136731

            1646039171228

               1. 获取所有的beanName,放入candidateNames数组
            
            1. 循环candidateNames数组,根据beanName获取beanDefinition,判断是否被处理过了。

            2. 判断是否是配置类,如果是,加入到configCandidates数组,在判断的时候还会标记配置类属于full还是lite配置类。

            3.1 当我们注册配置类的时候,可以加@Configuration,也可以加@Component,@ComponentScan,@Import,@ImportResource等注解,spring称这种配置为lite配置类,如果加了@Configuration就称之为full配置类。

            3.2 如果我们注册了lite配置类,getBean时会发现就是原本的配置类,如果我们注册full配置类,getbean时是一个cglib代理类。

            1646293396363

            1646293413912

            3.3 写一个A类,其中一个构造方法是打印”你好“ ,在一个配置类,有俩个被@Bean注解的方法,其中一个方法return new A(),命名为getA(),另一个方法调用getA(),如果配置类是lite配置类,会发现打印俩次你好,也就是说A类被new了俩次,如果配置类是Full类,会发现只打印一次”你好“,也就是说A类只被new了一次,因为这个类被cglib代理了,方法已经被改写。

      ​ 3.4 如果没有配置类会字节返回

      ​ 3.5 处理排序

      ​ 3.6 解析配置类,可能是full类,也可能是lite类

      ​ 3.7 在第六步的时候只是注册了部分Bean,但是如@Import@Bean,是没有被注册的。

      1646296574433

      因为可以有多个配置类,所以需要循环处理。我们的配置类的BeanDefinition是AnnotatedBeanDefinition的实例,所以会进入第一个

      if

      1646296796544

      1646296810928

      重点在于doProcessConfigurationClass方法,需要特别注意,最后一段代码,会把configClass放于一个map,

      1646297094798

    1646297127905

    1646297138520

    1646297150591

    1646297830625

    1646297843250

    1. 递归处理内部类,一般不会使用内部类。
    2. 处理@PropertySource注解,@ProertySource注解用来加载properties文件
    3. 获得componentscan注解具体的内容,componentscan注解出了最常用的basePackage之外,还有includeFilters,excludeFilters等
    4. 判断有没有被@ComponentScans标记,或者被@Condition条件带过,如果满足条件的话,进入if,进行如下操作。
      1. 执行扫描操作,吧扫描出来的放入set.
      2. 循环set,判断是否是配置类,是的话递归调用parse方法,因为被扫描出来的类,还是一个配置类,有@ComponentScan注解,或者其中有被@Bean标记的方法,等等,所以需要被再次解析。
    5. 处理@Import注解,他有三种情况,一种是import普通类,一种是importSelector,还有一种是 importBeanDefinitionRegistrar,getImports(sourceClass)是获得import的内容,返回的是一个set
    6. 处理@ImportResource注解
    7. 处理@Bean的方法,可以看到获得了带有@Bean的方法后,不是马上转化称beanDefinition,而是先用一个set接受

    1646299955312

    1646299973599

    1646299983615

    1646299994041

    1. 定义了一个扫描器scanner,常规方法中,实际上执行扫描只会是这里的scanner对象
    2. 处理includeFilters,就是把规则添加到scanner
    3. 处理excludeFilters,就是把规则添加到scanner.
    4. 解析basepackages,获得需要扫描哪些包。
    5. 添加一个默认的排除规则,拍出自己
    6. 执行扫描

    这里有一个补充说明,添加规则的时候,只是把具体的规则放入规则类的集合中去,规则类是一个函数式接口,之定义了一个虚方法的接口被称为函数式接口,这里只是把规则放进去,并没有真正执行这些规则。

    1646300404918

    1646300417203

    因为basePackages可能有多个,所以需要循环处理,最终会进行bean的注册,看一下findCandidateComponents

    1646300780992

    spring支持component索引技术,需要引入一个组件,大部分项目没引进,索引会进入scanCandidateComponents方法

    1646300832694

    1646300893127

    1646300903507

    1646301060269

    1646301078960

    1646375551158

    1646375555705

    1646375671962

    直到这里,才把configurationClassPostProcessor中的processConfigBeanDefinitions方法简单过一下,这里只会解析@Import的bean,不会注册。

    processConfigBeanDefinitions是BeanDefinitionRegistryPostProcessor接口中的方法,beanDefinitionRegistry后置处理器扩展了beanfactoryPostProcessor.postProcessBeanFactory是判断配置类是lite还是full,如果是full就会被cglib代理,目的是保证bean的作用域

    1646378173702

    总结:configurationClassPostProcessor中的processConfigBeanDefinitions主要是完成扫描,最终注册我们定义的bean.

    6.6 registerBeanPostProcessors(beanFactory)

    实例化和注册beanfactory中扩展了beanPostProcessor的bean.

    例如autowriedAnnotationBeanPostProcessor(处理被@Autowired修饰的bean并注入)

    requiredAnnotataionBeanPostProcessor(处理被@Requied注解修饰的方法)

    commonAnnotationBeanPostProcessor(处理@PreDestory,@Resource等多个注解的作用)等

    1646379655379

    6.7 initMessageSource()

    初始国际化资源处理器

    6.8 initapplicationEventMulticaster()

    //创建事件多播器

    1646379926959

    6.9 onRefresh()

    模板方法,在容器刷新的时候可以自定义逻辑,不同的spring容器做不同的事情

    6.10 registerListeners()

    注册监听器,广播early application events

    6.11 finishBeanfactoryInitialization(Beanfactory)

    实例化所有剩余的单例,懒加载除外

    比如invokeBeanfactorypostprocessorts方法中根据注解解析出来的的类,在这个时候都会被初始化。

    实例化的过程各种beanpostProcessor开始起作用。

    1646382063340

    上面这个方法是实例化懒加载单例bean的,也就是我们创建的bean

    1646382250129

    再看finishBeanFactoryInitialization这个方法,里面有一个beanFactory.preInstantiateSingletons()方法,顶进去之后一个接口,它的实现类是defaultListableBeanFactory,找到里面的getBean方法,这个方法 有一个分支,如果bean是fanctoryBean,对应处理。。。。如果bean不是factoryBean,对应处理。。。。不过不管是不是fanctoryBean最终都会调用getBean方法,直接调用doGetBean.

    1646383347075

    1646383360917

    这里面有一个createBean方法,有一个实现类为abstractAutowireCapableBeanFactory

    1646383797433

    创建实例

    1646383880537

    填充属性

    1646383895688

    1646383906912

    aware系列接口回调

    1646383926073

    1646383936077

    1646383943097

    1646383952672

    springBean的生命周期

    网上流传的一段

    1. 实例化bean对象,没有属性,
    2. 填充属性
    3. 如果bean实现了beanNameaware接口,调用setBeanName方法
    4. 如果bean实现了beanClassLoaderAware接口,则调用setBeanClassLoader方法
    5. 如果bean实现了beanFactoryAware接口,调用setBeanFactory方法
    6. 调用beanpostProccessor的postProcessBeforeInitialization方法。
    7. 如果bean实现了initializingBean接口,调用afterPropertiesSet方法
    8. 如果bean定义了Initializating接口,调用bean的init-method
    9. 调用beanpostProcessor的postProcessAfterInitialization方法。进行到这里,bean已经准备就绪,停留在应用的上下文中,知道被销毁
    10. 如果上下文被销毁了,如果bean实现了disposableBean接口,则调用destory方法,如果bean定义了destory-method声明了销毁方法也会被调用
    为了验证上面的逻辑,可以做个试验: 
    
    首先定义了一个Bean,里面有各种回调和钩子,其中需要注意下,我在SpringBean的构造方法中打印了 
    
    studentService,看SpringBean被new的出来的时候,studentService是否被注入了;又在 
    
    setBeanName中打印了studentService,看此时studentService是否被注入了,以此来验证,Bean是何时 
    
    完成的自动注入的(这个StudentServiceImpl 类的代码就不贴出来了,无非就是一个最普通的Bean)
    

    1646384652720

    1646384664707

    1646384673049

    1646384710715

    1646384732873

    1646384746404

    6-12 finishRefresh()

    refresh做完之后需要做的事情

    清楚上下文资源缓存(如扫描中的asm元数据)

    初始化上下文的生命周期处理器,并刷新。

    发布contextRefreshedEvent事件并告知对应的applicationListener进行相应的操作

    1646384912965

    1646384927424

    1646384936777

    1646384953115

    2.使用时间广播器广播事件到相应的监听器multicastEvent

    1646385084904

    3.2调用监听器invokeListener

    1646385129898

    1646385152724

    这样,当spring执行到finishrefresh方法时,就会将contextrefreshedEvent事件推送到myrefreshedListener中。跟contextRefreshedEvent相似的还有::ContextStartedEvent、ContextClosedEvent、

    ContextStoppedEvent,有兴趣的可以自己看看这几个事件的使用场景。当然也可以自定义监听事件,只需要继承applicationContextEvent抽象类即可

  • 相关阅读:
    spring-boot-starter-actuator /info获取空信息
    我们每天都在做无用功?
    Net和Java基于zipkin的全链路追踪
    各大厂分布式链路跟踪系统架构对比
    淘宝npm镜像使用方法(转)
    你离架构师还有多远?
    该怎么向别人介绍你们的系统架构?
    java中用MessageFormat格式化json字符串用占位符时出现的问题can't parse argument number
    你必须要了解的大数据潮流下的机器学习及应用场景
    突破GitHub单个文件最大100M的限制 LFS
  • 原文地址:https://www.cnblogs.com/xiaoshahai/p/16080730.html
Copyright © 2020-2023  润新知