springboot与spring相比,有一个劣势就是大部分配置都有一套默认设定,不用再写大量的配置文件,即“约定优于配置”。
而这是靠主动拆卸实现的。

一、主动加载入口

springboot的启动形式如下:

@SpringBootApplicationpublic class SpringRunner {    public static void main(String[] args) {        SpringApplication.run(SpringRunner.class, args);    }}

察看@SpringBootApplication注解

// ## 此注解非常重要@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {...}// ## 此注解同样重要@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {...}

从下面的代码看出,最终会通过@Import注解进入AutoConfigurationImportSelector类(调用链:@SpringBootApplication->@EnableAutoConfiguration->@Import(AutoConfigurationImportSelector.class))

持续察看:

// == 1.AutoConfigurationImportSelector实现DeferredImportSelector接//      调用getImportGroup()办法,返回AutoConfigurationGroup类public class AutoConfigurationImportSelector implements DeferredImportSelector{    @Override    public Class<? extends Group> getImportGroup() {        return AutoConfigurationGroup.class;    }}// == 2.实现DeferredImportSelector.Group接口    private static class AutoConfigurationGroup            implements DeferredImportSelector.Group{..}}

Group接口有两个办法:

// 加载配置信息void process(AnnotationMetadata metadata, DeferredImportSelector selector);// 包装成Entry对象并返回Iterable<Entry> selectImports();

接下来别离看一下这两个办法的实现。

1、process()办法——配置文件加载

@Overridepublic void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)      // == 配置加载      .getAutoConfigurationEntry(annotationMetadata);  this.autoConfigurationEntries.add(autoConfigurationEntry);  for (String importClassName : autoConfigurationEntry.getConfigurations()) {      this.entries.putIfAbsent(importClassName, annotationMetadata);  }}// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntryprotected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {    AnnotationAttributes attributes = getAttributes(annotationMetadata);    // 获取配置信息    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);        //...}// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurationsprotected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {    // ## spi形式加载配置    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,                getBeanClassLoader());    return configurations;}

之前介绍了spi配置加载,spi形式会查找META-INF下的spring.factories文件
文件内容:

# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\// ...省略...

依据org.springframework.boot.autoconfigure.EnableAutoConfiguration主动加载Redis、Mongo等156个默认配置

2、selectImports()办法——包装成Entry

@Overridepublic Iterable<Entry> selectImports() {    // 配置排序,并包装成Entry返回    return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()            .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))            .collect(Collectors.toList());}

二、spring初始化时加载Entry对象

Group接口selectImports()办法返回的Entry对象去了哪里?
其实spring初始化加载时会用到它们。

从spring的refresh办法(初始化外围办法)一路追踪,整个调用链如下:

AbstractApplicationContext # refreshAbstractApplicationContext # invokeBeanFactoryPostProcessorsPostProcessorRegistrationDelegate # invokeBeanFactoryPostProcessorsPostProcessorRegistrationDelegate # invokeBeanDefinitionRegistryPostProcessorsConfigurationClassPostProcessor # postProcessBeanDefinitionRegistryConfigurationClassPostProcessor # processConfigBeanDefinitionsConfigurationClassParser # parseConfigurationClassParser$DeferredImportSelectorHandler # processConfigurationClassParser$DeferredImportSelectorGroupingHandler # processGroupImports      ConfigurationClassParser$DeferredImportSelectorGrouping # getImports

这些Entry最终会以BeanDefinition对象的模式,放入到BeanDefinitionMap中。
后续进入spring bean对象初始化、属性赋值流程了,不再细说。