Spring源码分析-BeanDefination加载

ConfigurationClassPostProcessor

img

解析配置类中有两类集合,一类是配置类、另一类是所有已解析的bd

  1. 从已有bd中过滤配置类

candidateNames:保存已被解析出来的所有待解析的bd名

​ configCandidates:candidateNames经过过滤的所有待解析的配置类bd

​ 过滤条件:

​ 检查BeanDefinition并设置 CONFIGURATION_CLASS_ATTRIBUTEfull 或者 lite

Full : 即类被 @Configuration 注解修饰 && proxyBeanMethods属性为true (默认为 true)

Lite : 被 @Component、@ComponentScan、@Import、@ImportResource 修饰的类 或者 类中有被 @Bean修饰的方法

  1. configCandidates.sort()

  2. 解析配置类

​ candidates:configCandidates,待解析配置类

​ alreadyParsed:

​ do:
parse():解析,生成bd元数据(configClasses)

processConfigurationClass

​ 1.@Conditional条件过滤(PARSE_CONFIGURATION阶段)-> shouldSkip

​ 2.递归解析配置类

​ SourceClass sourceClass = asSourceClass(configClass, filter);
​ do:
​ sourceClass = doProcessConfigurationClass()
​ while (sourceClass != null);

​ 3.configurationClasses.put(configClasse)

this.deferredImportSelectorHandler.process()

​ DeferredImportSelectorGroupingHandler#register(DeferredImportSelectorHolder)

​ DeferredImportSelectorGroupingHandler#rprocessGroupImports

​ validate():校验配置类的访问权限...

​ configClasses:本次循环解析出来的配置类(其中可能包含已经被解析过的)

​ configClasses.removeAll(alreadyParsed)

loadBeanDefinitions():加载元数据为bd(configClasses)

​ alreadyParsed.addAll(configClasses)

​ candidates.clear()

​ newCandidateNames:所有已解析的bd名

​ oldCandidateNames:candidateNames

​ 遍历newCandidateNames:

​ 过滤掉oldCandidateNames(剩下本次解析出来bd)

​ 如果是配置类且没有被解析过,则加入candidates中

​ candidateNames = newCandidateNames

​ while (!candidates.isEmpty())

doProcessConfigurationClass

  1. 处理 @Component 注解

    如果类被 @Component 修饰,则处理内部类:

    processMemberClasses:寻找并遍历内部类中的配置类,递归解析

  2. 处理 @PropertySource 注解

    解析注解属性,根据注解属性中的locations,加载配置并添加到environment中

  3. 处理 @ComponentScan注解

    根据注解属性扫描指定的包,便遍历bd中的配置类,递归解析

  4. 处理 @Import 注解

    processImports(); 该方法处理的包括 @Import、ImportSelector、 ImportBeanDefinitionRegistrar。这三个注解或接口都可以完成Bean的引入功能。

    • ImportSelector:分为延迟加载(DeferredImportSelector)和非延迟加载

      • 非延迟加载会通过selectImports()方法,获取导入的类,并遍历导入的类递归的processImports进行解析

      • 延迟加载会调用 DeferredImportSelectorHandler.handle()

        deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, importSelector))
        
    • ImportBeanDefinitionRegistrar:并不立即进行解析,而是保存到 configClass 相应的属性中

    • @Import:可以通过 @Import(XXX.class) 的方式,将XXX作为configClass进行递归的解析

  5. 处理 @ImportResource 注解

    解析注解属性,保存到 configClass 相应的属性中

  6. 处理 @Bean修饰的方法

    解析注解属性,保存到 configClass 相应的属性中

  7. 处理其他默认接口方法

    检测 配置类实现的接口中的默认方法是否被@Bean修饰,如果被修饰则也需要保存到 configClass 中

  8. 处理父类,如果存在,递归解析

loadBeanDefinitions

  1. shouldSkip?
  2. 处理被引入的(被 @Import 或者其他配置类内部引入)的情况
  3. 处理BeanMethod
  4. 处理ImportResource
  5. 处理ImportBeanDefinitionRegistrar:执行loadBeanDefinitionsFromRegistrars()方法进行导入

shouldSkip(metadata, phase)

如果phase为null,则先判断是不是配置类,如果是则走PARSE_CONFIGURATION逻辑,否则走REGISTER_BEAN逻辑

  1. 获取@Conditional上所有Condition

  2. Condition集合排序

  3. 如果ConditionConfigurationCondition,需要condition.getConfigurationPhase()来获取该Condition生效的阶段

  4. 如果生效阶段为null或生效阶段与phase匹配,则返回!condition.matches:即条件不匹配的话,应该跳过

    matches(context, metadata)中,context包含BeanDefinitionRegistry,metadata为引入条件注解的注解元信息

deferredImportSelectorHandler.process()

DeferredImportSelector类结构图

image-20230505205015350

image-20230505210427825

  1. DeferredImportSelectorGroupingHandler#register(DeferredImportSelectorHolder)

    1. group = getImportGroup:获取DeferredImportSelector的Group,AutoConfigurationImportSelector对应的Group是AutoConfigurationGroup
    2. group -> new DeferredImportSelectorGrouping(createGroup(group)) 放入 groupings
    3. 将DeferredImportSelectorHolder填充到上边new的对象里
    4. configurationClasses.put
  2. DeferredImportSelectorGroupingHandler#rprocessGroupImports

    遍历groupings(DeferredImportSelectorGrouping):

    -> grouping.getImports():

​ 对deferredImports中每个DeferredImportSelectorHolder:使用绑定的group进行:

group.process(holder.getMetadata(),holder.getImportSelector())

​ 主要作用就是getAutoConfigurationEntry,获取spring。factories文件中自动配置类并保存到 entries中

​ 最后返回group.selectImports(),主要会通过配置文件中的条件进行过滤,这里返回的是Entry条目集合,最终每个条目结构为:image-20				230505213518197

对每个条目调用processImports进行处理,一般配置类只是个普通配置类,就会走processConfigurationClass这个方法进行处理

posted @ 2023-05-27 14:07  LEVRY  阅读(70)  评论(0)    收藏  举报