spring-ioc源码

### 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抽象类即可

posted @ 2022-03-31 10:49  小傻孩丶儿  阅读(148)  评论(0编辑  收藏  举报