SpringBoot IoC(2)配置类bean由来

578 阅读2分钟

配置类bean的由来

ConfigurationClassPostProcessor中的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法中,有如下代码:

    this.reader.loadBeanDefinitions(configClasses);
    alreadyParsed.addAll(configClasses);

这两句的作用是遍历configClasses,如果importedBy属性不为空,会将该类添加到IoC容器的beanDefinitionMap和beanDefinitionNames变量中,然后将上图中下面三个属性涉及到的bean添加到bdm和bdn。configClasses是parser的configurationClasses(key-value键值对)的键集合,在扫描的时候,会将每一次解析所对应的bean添加到configurationClasses变量中,然而发现不止这么多,因而产生了疑问:那些多余的configurationClasses如何而来?

往上追溯进入parser.parse(candidates),发现是this.deferredImportSelectorHandler.process()这一句起的作用。

// deferred是延迟的意思
ConfigurationClassParser->DeferredImportSelectorHandler->process():
    handler.processGroupImports();    
ConfigurationClassParser->DeferredImportSelectorGroupingHandler->processGroupImports():
    grouping.getImports()
ConfigurationClassParser->DeferredImportSelectorGrouping->getImports():
    this.group.process(deferredImport.getConfigurationClass().getMetadata(),
        deferredImport.getImportSelector());
AutoConfigurationImportSelector->AutoConfigurationGroup->process():
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
        .getAutoConfigurationEntry(getAutoConfigurationMetadata(),
            annotationMetadata);
AutoConfigurationImportSelector->getAutoConfigurationEntry():
    List<String> configurations = getCandidateConfigurations(annotationMetadata,
        attributes);
AutoConfigurationImportSelector->getCandidateConfigurations():
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
SpringFactoriesLoader->loadFactoryNames():
    String factoryClassName = factoryClass.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());

在SpringFactoriesLoader类中,loadSpringFactories(classLoader)返回的是key-value的键值对,factoryClassName的值为org.springframework.boot.autoconfigure.EnableAutoConfiguration,在这边初步拿到这些bean集合(假设为下图中的125个)。然后遍历,如果有真正的类,则使用Class.forName加载,加载成功返回true,否则返回false,最终剔除掉为false的bean。

附录:SpringFactoriesLoaderloadFactoryNames方法:

假设classLoader不为空,则依次读取jar包下的META-INF/spring.factories文件,以下图为例:

result是一个map集合,与之一一对应,在读取不同的spring.factories文件时,如果存在相同的key,则合并。

根据传过来的factoryClass得到它的全限定名,如注解EnableAutoConfiguration的全限定名为org.springframework.boot.autoconfigure.EnableAutoConfiguration。 当key为它时,返回图一中的125个

总结

万始之源:启动类下的@EnableAutoConfiguration注解

  1. 找到配置类bean
  2. jar包没有引入则剔除(使用Class.forName实现)
  3. 解析配置类,加入到configurationClasses
  4. 遍历configurationClasses,将发现的bean添加到容器的到bdm和bdn变量中