美文网首页
【Spring源码】17.IOC之ConfigurationCl

【Spring源码】17.IOC之ConfigurationCl

作者: 天还下着毛毛雨 | 来源:发表于2023-02-05 11:14 被阅读0次
    image

    3.1 前言

    当 需要解析的 BeanDefinition集合收集完毕后,,接下来就会 遍历 这个集合里的每一个 BeanDefinition,

    解析@Component,@PropertySource,@ComponentScan, @Import,@ImportResource, @Bean,等注解,将各注解的解析结果存入对应的容器,以待后续进一步处理。

    image

    把元数据对象和beanName封装成ConfigurationClass 对象,继续往下走

    image

    会先进行@Conditional注解的判断,如果不符合,就会跳过,符合就继续往下走

    image

    3.1 解析 @Component

    这个主要是为了 解析该类的内部类 ,如果内部类有 @Component / @ComponentScan / @Import / @ImportResource 注解,需要去解析这个类

    image

    取出内部类,判断有没有 @Component / @ComponentScan / @Import / @ImportResource

    image

    判断的条件的话还是 和一开始过滤的时候一样,会有一个需要解析的注解数组 来匹配

    image

    就是这四个注解

    image

    匹配到了,说明这个内部类需要解析,

    把他封装成 ConfigurationClass 对象,ConfigurationClass importBy 等于他的外部类的ConfigurationClass对象 ,beanName是为空的

    如果是别其他类带进来的 bean类,此时的ConfigurationClass 的beanName都是为Null.

    传入 这个 ConfigurationClass 对象 ,递归调用 processConfigurationClass 去解析它,流程一样。

    image

    最后加入到ConfigurationClassParser 对象的configurationClasses map列表中, 待内部类的解析流程走完,外部类 走完也会加入到 这个map中。

    所以,外部类和内部类全部解析完, map列表是这样的

    image

    3.2 解析 @PropertySource

    @PropertySource 注解 用来 导入 配置文件,将配置文件的信息 纳入到配置环境中

    image

    根据配置的 配置文件路径,创建PropertySource对象,然后加入到Environment对象中

    image 加入或者 替换 environment里的 propertySources :配置文件列表 image

    3.3 解析 @ComponentScan

    该doProcessConfigurationClass方法继续往下走

    如果该类有 @ComponentScan 注解,同样的也是 创建一个 扫描器,扫 @ComponentScan配置的包下 是否有符合的类 需要注册,返回 BeanDefinitionHolder集合。

    然后调用 ConfigurationClassUtils.checkConfigurationClassCandidate() 方法判断 每个 beanDefinition 是否需要被解析,和第二点开始哪里判断的一样:

    是否有@Configuration 注解 + 是否有 @Component / @ComponentScan / @Import / @ImportResource

    image

    如果需要解析,递归 parse 方法,重新开始解析,

    最后都加入到ConfigurationClassParser 对象的configurationClasses map列表

    3.4 解析 @Import

    @Import 可以导入一个类,让他注册到spring容器中

    image

    3.4.1 getImports(sourceClass) ,收集所有@Import 进来的类

    这个方法会收集所有的@Import里面配置的类,封装成SourceClass对象,装进集合中

    image image

    如果收集的@Import进来的类不为空,就开始遍历这些类

    3.4.2 如果Import进来的是ImportSelector 接口类型

    ImportSelector 接口 : selectImports 会返回一串类的 全限定名称, 在该解析过程中,这个过程中会被调用,并导入这些类

    public interface ImportSelector {
       String[] selectImports(AnnotationMetadata importingClassMetadata);
    }
    

    会先实例化这个类,判断是不是 DeferredImportSelector 类型的

    1. 如果是 DeferredImportSelector 类型

    把他加入到ConfigurationClassParser对象的deferredImportSelectorHandler属性的deferredImportSelectors 集合中

    image

    2. 如果只是单纯的 ImportSelector 类型

    调用ImportSelector接口的selectImports,返回一串类的 全限定名称数组,获取class对象,封装成SourceClass集合,递归调用 @Import的解析流程,导入他们所要导入的类

    image

    最后都加入到ConfigurationClassParser 对象的configurationClasses map列表

    importBy属性为导入他的类的ConfigurationClass对象

    image

    3.4.3 如果Import进来的是ImportBeanDefinitionRegistrar 接口类型

    1. ImportBeanDefinitionRegistrar 作用

    ImportBeanDefinitionRegistrar接口,如果被导入进来的类是 实现了这个接口,那么在该解析过程中, 会被调用到 registerBeanDefinitions 方法,会传入 导入他的类的 元数据AnnotationMetadata对象 和 BeanDefinitionRegistry 对象。

    public interface ImportBeanDefinitionRegistrar {
    
       default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
       }
    
    }
    

    这个接口用处挺重要的:往往用来导入一些其他的类进来

    AnnotationMetadata 对象 可以获取导入他的类的元数据,用来获取注解的配置信息等

    BeanDefinitionRegistry对象 : 用来注册其他类

    比如 mybatis的@MapperScan 注解

    image

    注解mapper接口的BeanDefinition对象到 spring容器中

    image

    2.实例化该ImportBeanDefinitionRegistrar 实例,放入导入他的类的ConfigurationClass的importBeanDefinitionRegistrars集合里

    image

    3.4.4 导入的类 没有实现以上接口

    封装被导入的类为ConfigurationClass对象,递归processConfigurationClass 方法,重头解析被导入的类 的 以上所有注解。

    image

    最后都加入到ConfigurationClassParser 对象的configurationClasses map列表中

    3.5 解析@ImportResource

    解析完@Import注解后,开始解析@ImportResource,@ImportResource可以导入一个applicationContext的xml文件,注册里面配置的类

    image

    3.6 解析@Bean

    接下来解析@Bean

    image

    获取所有有@Bean注解的方法

    image

    遍历,封装成BeanMethod对象 ConfigurationClassParser 加到ConfigClass.beanMethods容器中

    image

    至此,所有的解析工作都已完成。

    3.7 解析结果与对应存放的容器小结

    1.configurationClassParser的 configurationClasses

    有@Component注解的类 和他需要导入类的内部类

    有 @ComponentScan 注解的类 和他扫描到的 所有类

    有 @Import注解的类 和 他导进来的所有类 (除导进来的是DeferredImportSelector,ImportBeanDefinitionRegistrar 接口)

    封装成ConfigurationClass, 会放在ConfigurationClassParser的 configurationClasses属性中

    private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
    

    2.ConfigurationClassParser.deferredImportSelectorHandler.deferredImportSelectors

    导进来的 DeferredImportSelector接口类

    放在 ConfigurationClassParser对象的deferredImportSelectorHandler属性的deferredImportSelectors 集合中

    private final DeferredImportSelectorHandler deferredImportSelectorHandler = new DeferredImportSelectorHandler();
    
    private class DeferredImportSelectorHandler {
    
       @Nullable
       private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
      
    }
    

    3.ConfigurationClassParser.configurationClasses[n].importBeanDefinitionRegistrars

    导进来的 ImportBeanDefinitionRegistrar 接口类型

    放在ConfigurationClass的importBeanDefinitionRegistrars

    private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars ;
    

    4.ConfigurationClass.beanMethods

    @Bean 注解的方法 封装成 BeanMethod

    放在ConfigurationClass的 beanMethods 中

    private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
    

    4.DeferredImportSelector接口的调用

    image

    最终也是会调到我们自己被@Import进来的DeferredImportSelector实现类的selectImports方法里

    image

    只不过他里面要经过 DeferredImportSelector.Group的操作,比较复杂,碍于文章篇幅,这里就先略过了。

    相关文章

      网友评论

          本文标题:【Spring源码】17.IOC之ConfigurationCl

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