为了给组里的实习生妹妹讲怎样自界说SpringbootStarter

我觉得需求让她先知道Springboot的主动安装机制,

但又感觉是不是得先让她了解SpringSPI机制,

最后又觉得还有必要阐明一下一个@Configuration装备类在Spring中怎样被解析,这又会引出对ConfigurationClassPostProcessor的讲解,

完了,收不住了,到处都是常识盲区。

常识盲区脑图如下。

一文学会Springboot的自动装配机制

往期文章

文学会Spring的@Configuration装备类解析


前言

何谓Springboot的主动安装,简要归纳便是:引进第三方组件的starter包后可以主动将第三方组件的bean加载到IOC容器中供用户使用。

主动安装的机制是Springboot供给的,因而第三方组件的starter包在编写的时分,就需求依据Springboot的主动安装的规矩来编写starter包,那么这儿的规矩归纳如下。

  1. starter包需求在/META-INF/目录下供给spring.factories文件;
  2. spring.factories文件中以Key-Values的形式来供给需求Springboot去加载的类的全限定名。这儿的Key便是Springboot中各种扩展点的全限定名,比如org.springframework.boot.autoconfigure.EnableAutoConfiguration,然后Values便是starter包中供给的扩展点的一切类的全限定名,以逗号隔开。

只需第三方组件的starter包依照上述规矩来编写,那么Springboot就可以将starter包供给的各种扩展点的类进行加载,例如下面的这个spring.factories文件。

org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\

啥意思呢,其实便是第三方组件的starter包在告诉Springboot:嘿,亲爱的Springboot,我供给了一个监听器,它的全限定名是org.springframework.boot.autoconfigure.BackgroundPreinitializer,托付你去加载它;嘿,亲爱的Springboot,我供给了多个主动装备类,它们的全限定名是org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfigurationorg.springframework.boot.autoconfigure.aop.AopAutoConfigurationorg.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,托付你去加载它们。

Springboot的主动安装机制解释起来很简略,使用起来也巨方便,关于主动安装的详细使用,将在后续的自界说starter包一文中进行演示。

本文的重点是Springboot的主动安装机制的底层原理,废话不多说,开造。

Springboot版本:2.4.1

正文

一. 知道@SpringBootApplication注解

咱们新建一个Springboot使用,都需求一个发动类,然后在发动类上添加@SpringBootApplication注解,那么来看一下@SpringBootApplication注解的组成。

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {}

也便是说@SpringBootApplication是由@SpringBootConfiguration,@EnableAutoConfiguration和@ComponentScan组成的复合注解,下面是对这三个注解的阐明。

  • @SpringBootConfiguration标明Springboot发动类是一个装备类;
  • @ComponentScan注解会将指定途径下的被特定注解润饰的类加载为Spring中的bean,这些特定注解为@Component,@Controller,@Service,@Repository和@Configuration注解;
  • @EnableAutoConfiguration注解用于敞开Springboot的主动安装。

也便是说,相当于咱们在Springboot使用的发动类上添加了一个叫做@EnableAutoConfiguration的注解,从而敞开了主动安装功用。

那么再看一下@EnableAutoConfiguration注解的组成。

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

@EnableAutoConfiguration注解也是一个复合注解,主要功用由@AutoConfigurationPackage注解和@Import注解完结,那么必定的,主动安装,便是这两个注解完结的。

二. @AutoConfigurationPackage注解

先给出结论。

@AutoConfigurationPackage注解作用在Springboot发动类上,会向Spring容器注册一个类型为AutoConfigurationPackages.BasePackagesbean,这个bean中保存了Springboot发动类的包途径,后续Springboot就会扫描这个包途径下由@Component,@Controller,@Service,@Repository和@Configuration注解润饰的类。

下面开始剖析原理。

@AutoConfigurationPackage注解的功用由@Import(AutoConfigurationPackages.Registrar.class) 完结,所以看一下AutoConfigurationPackages.Registrar的类图,如下所示。

一文学会Springboot的自动装配机制

所以AutoConfigurationPackages.Registrar实际是一个ImportBeanDefinitionRegistrar,那么在Spring容器发动过程中,会调用到AutoConfigurationPackages.RegistrarregisterBeanDefinitions() 办法向注册表注册一个BeanDefinitionregisterBeanDefinitions() 办法如下所示。

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}

registerBeanDefinitions() 办法中调用了AutoConfigurationPackagesregister() 办法,register() 办法的第二个参数是经过new PackageImports(metadata).getPackageNames() 获取,其实便是将被@AutoConfigurationPackage注解润饰的类的包途径回来。

现在看一下register() 办法的完结,如下所示。

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
    if (registry.containsBeanDefinition(BEAN)) {
        BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition) registry.getBeanDefinition(BEAN);
        beanDefinition.addBasePackages(packageNames);
    }
    else {
        registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
    }
}

register() 办法中会将包途径packageNames封装成一个BasePackagesBeanDefinition,然后注册到注册表中。下面看一下BasePackagesBeanDefinition的构造办法,如下所示。

BasePackagesBeanDefinition(String... basePackages) {
    setBeanClass(BasePackages.class);
    setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    addBasePackages(basePackages);
}

BasePackagesBeanDefinition的构造办法中,将beanClass设置为了BasePackages.class,那么后续会依据BasePackagesBeanDefinition向容器注册一个类型为BasePackagesbean,而且BasePackagesbean中的packages字段是一个包途径的调集。

最后阐明一下,BasePackagesBeanDefinitionBasePackages都是AutoConfigurationPackages的静态内部类,类图如下。

一文学会Springboot的自动装配机制

三. AutoConfigurationImportSelector

@EnableAutoConfiguration注解完结主动安装主要便是依托@Import(AutoConfigurationImportSelector.class),下面先看一下AutoConfigurationImportSelector的类图。

一文学会Springboot的自动装配机制

所以AutoConfigurationImportSelector是一个DeferredImportSelector,那么在ConfigurationClassParserparse(Set<BeanDefinitionHolder> configCandidates) 办法中会敞开处理AutoConfigurationImportSelector的逻辑。

parse(Set<BeanDefinitionHolder> configCandidates) 如下所示。

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            if (bd instanceof AnnotatedBeanDefinition) {
                // 初始装备类对应的BeanDefinition为AnnotatedGenericBeanDefinition
                // AnnotatedGenericBeanDefinition完结了AnnotatedBeanDefinition接口
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            else {
                parse(bd.getBeanClassName(), holder.getBeanName());
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
        }
    }
    // 推迟处理DeferredImportSelector
    this.deferredImportSelectorHandler.process();
}

deferredImportSelectorHandler字段类型为DeferredImportSelectorHandler,是ConfigurationClassParser的一个内部类,其process() 办法如下所示。

public void process() {
    // DeferredImportSelectorHolder对ConfigurationClass和DeferredImportSelector进行了简略封装
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    try {
        if (deferredImports != null) {
            // DeferredImportSelectorGroupingHandler是ConfigurationClassParser的内部类
            // 用于分组处理DeferredImportSelector,这儿的组指DeferredImportSelector的内部接口Group
            // Group接口的作用是用于对不同ImportSelector的导入成果进行分组
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            // 对deferredImports进行排序
            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
            // 分组地将DeferredImportSelector注册到DeferredImportSelectorGroupingHandler中
            deferredImports.forEach(handler::register);
            // 调用DeferredImportSelectorGroupingHandler的processGroupImports()办法分组处理DeferredImportSelector
            handler.processGroupImports();
        }
    }
    finally {
        this.deferredImportSelectors = new ArrayList<>();
    }
}

DeferredImportSelectorHolder是对ConfigurationClassDeferredImportSelector进行的简略封装,在DeferredImportSelectorHandler#process办法中,先获取到一切的DeferredImportSelector,然后创立DeferredImportSelectorGroupingHandler用于处理DeferredImportSelectorDeferredImportSelectorGroupingHandler会先注册DeferredImportSelectorDeferredImportSelectorGroupingHandlergroupings字段中,然后调用DeferredImportSelectorGroupingHandler#processGroupImports办法处理groupings字段中的DeferredImportSelector,而且整个处理是按组进行处理的,这儿的组其实便是DeferredImportSelector的内部接口GroupDeferredImportSelector接口的完结类完结的getImportGroup() 办法就需求回来一个Group接口的完结类的Class目标,一般如下所示。

public class MyDeferredImportSelector implements DeferredImportSelector {
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[0];
    }
    public Predicate<String> getExclusionFilter() {
        return null;
    }
    public Class<? extends Group> getImportGroup() {
        // 回来MyGroup的Class目标
        return MyGroup.class;
    }
    // 界说一个内部类而且完结DeferredImportSelector的内部接口Group
    private static class MyGroup implements DeferredImportSelector.Group {
        @Override
        public void process(AnnotationMetadata metadata, DeferredImportSelector selector) {
        }
        @Override
        public Iterable<Entry> selectImports() {
            return new ArrayList<>();
        }
    }
}

那么现在看一下DeferredImportSelectorGroupingHandler是怎样注册DeferredImportSelectorDeferredImportSelectorGroupingHandlergroupings字段中的。

DeferredImportSelectorGroupingHandler#register办法如下所示。

public void register(DeferredImportSelectorHolder deferredImport) {
    // 获取Group接口的完结类的Class目标
    Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
    // 将Group接口的完结类进行实例化,然后封装成DeferredImportSelectorGrouping目标
    // 以Group接口的完结类的Class目标为键,DeferredImportSelectorGrouping目标为值,注册到groupings字段中
    DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
            (group != null ? group : deferredImport),
            key -> new DeferredImportSelectorGrouping(createGroup(group)));
    // 为当时Group接口的完结类对应的DeferredImportSelectorGrouping添加DeferredImportSelector
    grouping.add(deferredImport);
    this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
            deferredImport.getConfigurationClass());
}

DeferredImportSelectorGroupingHandlergroupings字段是一个map结构,键是Group接口的完结类的Class目标,值是DeferredImportSelectorGrouping目标,而DeferredImportSelectorGrouping目标是对Group接口的完结类的实例和DeferredImportSelector的封装,那么上面的DeferredImportSelectorGroupingHandler#register办法其实便是将相同组的DeferredImportSelector悉数放到同一个DeferredImportSelectorGrouping目标中,然后再将DeferredImportSelectorGrouping目标注册到DeferredImportSelectorGroupingHandlergroupings字段中。

那么怎样才算是相同组的DeferredImportSelector,其实便是DeferredImportSelectorgetImportGroup() 办法回来相同的Class目标。

现在再看一下DeferredImportSelectorGroupingHandler是怎样处理DeferredImportSelector的,DeferredImportSelectorGroupingHandler#processGroupImports办法如下所示。

public void processGroupImports() {
    // 遍历每一个DeferredImportSelectorGrouping,即按组来处理DeferredImportSelector
    for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
        Predicate<String> exclusionFilter = grouping.getCandidateFilter();
        // 经过grouping.getImports()获取到当时组里一切DeferredImportSelector导入的类
        // 然后将每个导入的类封装成一个ConfigurationClass然后进行解析
        grouping.getImports().forEach(entry -> {
            ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
            try {
                // 调用到ConfigurationClassParser的processImports()办法进入递归解析流程
                processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
                        Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
                        exclusionFilter, false);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                                configurationClass.getMetadata().getClassName() + "]", ex);
            }
        });
    }
}

DeferredImportSelectorGroupingHandler#processGroupImports办法中是分组进行处理,每次将一组中的一切DeferredImportSelector导入的类获取出来,然后将每个导入的类封装成ConfigurationClass,后续便是处理ConfigurationClass的逻辑。

现在看一下DeferredImportSelectorGroupinggetImports() 办法的详细完结,如下所示。

public Iterable<Group.Entry> getImports() {
    // 先遍历当时组的每个DeferredImportSelector,并经过Group接口的完结类的process()办法进行处理
    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
        this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                deferredImport.getImportSelector());
    }
    // 然后调用Group接口的完结类的selectImports()办法回来一切需求导入的类
    // 这些需求导入的类会被封装成Group.Entry目标
    return this.group.selectImports();
}

DeferredImportSelectorGroupinggetImports() 办法会先调用Group接口的完结类的process() 办法处理组里的每个DeferredImportSelector,然后再调用Group接口的完结类的selectImports() 办法获取一切需求导入的类,每个需求被导入的类会被封装成Group.Entry目标并回来。先剖析AutoConfigurationImportSelector中的组目标AutoConfigurationGroupprocess() 办法,完结如下。

public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
            () -> String.format("Only %s implementations are supported, got %s",
                    AutoConfigurationImportSelector.class.getSimpleName(),
                    deferredImportSelector.getClass().getName()));
    // 调用AutoConfigurationImportSelector的getAutoConfigurationEntry()办法获取一切需求主动安装的组件的装备类的全限定名
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
            .getAutoConfigurationEntry(annotationMetadata);
    // 添加到组目标AutoConfigurationGroup的autoConfigurationEntries调集中
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
        this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}

继续剖析AutoConfigurationImportSelectorgetAutoConfigurationEntry() 办法,看一下一切需求主动安装的组件的装备类的全限定名是怎样获取的。

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    // 获取@EnableAutoConfiguration注解的元数据特点
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 将需求主动安装的组件的装备类的全限定名获取出来
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 去除重复的组件
    configurations = removeDuplicates(configurations);
    // 去除被排除的组件
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    // 去除依靠项不满足的组件
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 回来剩余的需求主动安装的组件的装备类的全限定名
    return new AutoConfigurationEntry(configurations, exclusions);
}

AutoConfigurationImportSelectorgetAutoConfigurationEntry() 办法是先将一切需求主动安装的组件的装备类的全限定名获取出来,然后进行去重和条件过滤。AutoConfigurationImportSelectorgetAutoConfigurationEntry() 办法中,最重要的便是getCandidateConfigurations() 办法,其完结如下。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // getSpringFactoriesLoaderFactoryClass()的回来值是EnableAutoConfiguration.class
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
            getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
            + "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

SpringFactoriesLoaderSpringSPI机制的完结类,Springboot可以完结组件主动安装便是依靠的SpringFactoriesLoader,下面剖析一下SpringFactoriesLoader#loadFactoryNames办法,如下所示。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    ClassLoader classLoaderToUse = classLoader;
    if (classLoaderToUse == null) {
        classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
    }
    // 这儿factoryTypeName为org.springframework.boot.autoconfigure.EnableAutoConfiguration
    String factoryTypeName = factoryType.getName();
    // loadSpringFactories()办法会先依据ClassLoader从缓存中获取需求主动安装的组件信息
    // 获取不到则使用ClassLoader将classpath下一切jar包的一切META-INF/spring.factories文件中的信息加载
    // loadSpringFactories()办法获取出来的数据是一个Map
    // 形式为Map[factoryTypeName, List[主动安装的组件的装备类的全限定名]]
    return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

SpringFactoriesLoader#loadFactoryNames办法中调用了loadSpringFactories() 办法依据ClassLoader来将需求主动安装的组件的装备类的全限定名获取出来,一切classpath下的jar包中的META-INF/spring.factories文件都会被扫描。loadSpringFactories() 办法完结如下。

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
    // 先依据ClassLoader从缓存中获取
    // Map[factoryTypeName, List[主动安装的组件的装备类的全限定名]]
    Map<String, List<String>> result = cache.get(classLoader);
    if (result != null) {
        return result;
    }
    result = new HashMap<>();
    try {
        // 将一切META-INF/spring.factories文件途径获取出来
        Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            UrlResource resource = new UrlResource(url);
            // 将spring.factories文件的内容读取成Properties,Properties实质是一个HashTable
            Properties properties = PropertiesLoaderUtils.loadProperties(resource);
            // 将Properties的内容添加到result
            for (Map.Entry<?, ?> entry : properties.entrySet()) {
                String factoryTypeName = ((String) entry.getKey()).trim();
                String[] factoryImplementationNames =
                        StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
                for (String factoryImplementationName : factoryImplementationNames) {
                    result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
                            .add(factoryImplementationName.trim());
                }
            }
        }
        result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
                .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
        // 缓存到cache中
        cache.put(classLoader, result);
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load factories from location [" +
                FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
    return result;
}

下面再给出spring-boot-autoconfigure包下的spring.factories文件的部分内容,就可以知道上面的loadSpringFactories() 办法的回来值详细是什么结构。

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
......

因而loadSpringFactories() 办法的回来值map的键可以是上述的org.springframework.boot.autoconfigure.AutoConfigurationImportFilter,或者org.springframework.boot.autoconfigure.EnableAutoConfiguration等,值便是一个全限定名的调集。所以在SpringFactoriesLoader#loadFactoryNames办法中可以经过loadSpringFactories() 办法的回来值拿到org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的需求主动安装的装备类的全限定名的调集。

现在继续剖析AutoConfigurationImportSelector中的组目标AutoConfigurationGroupselectImports() 办法,如下所示。

public Iterable<Entry> selectImports() {
    if (this.autoConfigurationEntries.isEmpty()) {
        return Collections.emptyList();
    }
    Set<String> allExclusions = this.autoConfigurationEntries.stream()
            .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
    // 将组中每个DeferredImportSelector导入的类的全限定名获取出来
    // 这儿导入的类便是需求主动安装的组件的装备类
    Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
            .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
            .collect(Collectors.toCollection(LinkedHashSet::new));
    processedConfigurations.removeAll(allExclusions);
    return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
            .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
            .collect(Collectors.toList());
}

因为组里会有多个DeferredImportSelector,而每个DeferredImportSelector会在AutoConfigurationGroupprocess() 办法中生成一个AutoConfigurationEntry,所以上面的办法便是将每个DeferredImportSelector对应的AutoConfigurationEntry中的全限定名的调调集并到一个调集中并回来。

至此,AutoConfigurationImportSelector全体的一个处理流程剖析结束。

整个剖析流程很长,但是假如耐着性质看完,会发现整个流程可以用下图进行归纳。

一文学会Springboot的自动装配机制

总结

Springboot的主动安装功用由@EnableAutoConfiguration注解供给。

而@EnableAutoConfiguration注解的功用主要由以下两部分完结。

一. @AutoConfigurationPackage

@AutoConfigurationPackage注解作用在Springboot发动类上,会向Spring容器注册一个类型为AutoConfigurationPackages.BasePackagesbean,这个bean中保存了Springboot发动类的包途径,后续Springboot就会扫描这个包途径下由@Component,@Controller,@Service,@Repository和@Configuration注解润饰的类。

二. @Import(AutoConfigurationImportSelector.class)

  1. @Import(AutoConfigurationImportSelector.class) 会经过AutoConfigurationImportSelector推迟且分组的向Spring容器导入需求主动安装的组件的装备类,从而在解析这些装备类的时分可以将主动安装的组件的bean注册到容器中;
  2. 所谓的推迟,是因为AutoConfigurationImportSelector完结了DeferredImportSelector接口,其逻辑会在Springboot发动类被解析结束后才会履行;
  3. 所谓的分组,是因为处理DeferredImportSelector是一组一组的进行的,只需DeferredImportSelector的完结类完结的getImportGroup() 办法回来的Class目标相同,那么这样的DeferredImportSelector的完结类就属于同一组;
  4. AutoConfigurationImportSelector获取到需求主动安装的组件的装备类的全限定名,是经过SpringFactoriesLoader完结的,而SpringFactoriesLoader便是Spring中的SPI机制的完结。

假如觉得本篇文章对你有帮助,求求你点个赞,加个保藏最后再点个关注吧。创造不易,感谢支撑!


本文正在参加「金石方案」