Spring Boot源码(六) - 自动装配(下)- AutoConfigurationImportSelector

目录

一、process

1、getAutoConfigurationMetadata

2、getAutoConfigurationEntry

1)、获取EnableAutoConfiguration注解的exclude和excludeName属性值

2)、获取spring.factories中EnableAutoConfiguration的配置值

3)、removeDuplicates(去重)

4)、获取需要排除(不自动装配)的类

5)、checkExcludedClasses(检查需要排除的项目)

6)、剔除排除项

6)、发送AutoConfigurationImportEvent事件

7)、创建AutoConfigurationEntry对象返回

二、selectImports


    继续上一篇,知道了执行时机和调用顺序,继续分析两个方法的逻辑,是怎样实现自动装配的。开始之前先看看其类结构(属性)AutoConfigurationImportSelector.AutoConfigurationGroup

private static class AutoConfigurationGroup
			implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
    // 存储注解对象关系
    private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
    // 存储自动装配的数据
    private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();

    private ClassLoader beanClassLoader;

    private BeanFactory beanFactory;

    private ResourceLoader resourceLoader;
    // 存储自动装配的,后置处理器,默认order值等信息
    private AutoConfigurationMetadata autoConfigurationMetadata;
}

一、process

@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    // 断言判断,肯定为true
    Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, // 省略部分代码);
    // 向上转型,调用父类的方法
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
            .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
    // 添加到autoConfigurationEntries属性中
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    // 将bean信息添加到entries(Map<String, AnnotationMetadata>)中
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
        this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}

    获取AutoConfigurationEntry类型的返回结果,组装数据到AutoConfigurationGroup的autoConfigurationEntries和entries中。主要的方法在getAutoConfigurationMetadata中,但是在调用前会加载autoConfigurationMetadata数据。

1、getAutoConfigurationMetadata

private AutoConfigurationMetadata getAutoConfigurationMetadata() {
    if (this.autoConfigurationMetadata == null) {
        this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
    }
    return this.autoConfigurationMetadata;
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
    // String PATH = "META-INF/spring-autoconfigure-metadata.properties";
    return loadMetadata(classLoader, PATH);
}

static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
    try {
        Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
                : ClassLoader.getSystemResources(path);
        Properties properties = new Properties();
        while (urls.hasMoreElements()) {
            properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
        }
        return loadMetadata(properties);
    }
    catch (IOException ex) {
        throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
    }
}

    查询的文件路径为 "META-INF/spring-autoconfigure-metadata.properties",总共有488项key、value对应值。并将其值加载成为Properties类型数据。先看看配置文件大概的内容:

org...RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration

org...CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate

org...JerseyAutoConfiguration.AutoConfigureOrder=-2147483648

    大致有三种类型(为后续spring.factories中的自动装配类,进行条件判断,过滤使用):

1)、...XXAutoConfiguration.AutoConfigureAfter    谁的自动装配的后置处理器类型

2)、...XXAutoConfiguration.ConditionalOnClass   谁的自动装配的装配条件

3)、...XXAutoConfiguration.AutoConfigureorder    谁的自动装配的排序字段值

 

    再继续看看最后加装的类型(最好加装为PropertiesAutoConfigurationMetadata类型,存放到Spring的Properties类型中,就是一个Hashtable):

static AutoConfigurationMetadata loadMetadata(Properties properties) {
    return new PropertiesAutoConfigurationMetadata(properties);
}

 

2、getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
                                                           AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    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 = filter(configurations, autoConfigurationMetadata);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

1)、获取EnableAutoConfiguration注解的excludeexcludeName属性值

    只是默认情况下使用@EnableAutoConfiguration直接都是直接使用的@SpringBootApplication,所以获取到的属性值都为默认值(为空)。

protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
    // org.springframework.boot.autoconfigure.EnableAutoConfiguration
    String name = getAnnotationClass().getName();
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
    Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
            + " annotated with " + ClassUtils.getShortName(name) + "?");
    return attributes;
}

2)、获取spring.factories中EnableAutoConfiguration的配置值

    在调用前需要查看加载的类型:

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    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;
}

    在启动Spring Boot项目时,分析过会加载META-INF/spring.factories中的所有配置信息。正确流程情况下会在SpringApplic

ation.run方法中,加载SpringApplicationRunListener类型时就会去加载该properties中的信息,其中有一项大致为:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
。。。。。。

 

3)、removeDuplicates(去重)

protected final <T> List<T> removeDuplicates(List<T> list) {
    return new ArrayList<>(new LinkedHashSet<>(list));
}

    虽然比较简单,但是是我们在写项目的时候可以进行借鉴的方式。

4)、获取需要排除(不自动装配)的类

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    Set<String> excluded = new LinkedHashSet<>();
    excluded.addAll(asList(attributes, "exclude"));
    excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
    excluded.addAll(getExcludeAutoConfigurationsProperty());
    return excluded;
}

    不仅处理了之前getAttributes加载的@EnableConfiguration上的配置值,还添加了getExcludeAutoConfigurationsProperty中,在Environment中加载的值。当然,默认情况下所有值都为空。

5)、checkExcludedClasses(检查需要排除的项目)

    循环遍历排除项,如果在自动装配项中不存在需要排除的项,则组装检查异常IllegalStateException并抛出。所以不能随便写排除项。

6)、剔除排除项

// 根据上面的排除项集合,剔除排除项
configurations.removeAll(exclusions);
// 根据加载的spring-autoconfigure-metadata.properties条件,进行排除
configurations = filter(configurations, autoConfigurationMetadata);
private List<String> filter(List<String> configurations, AutoConfigurationMetadata 
    autoConfigurationMetadata) {

    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
        invokeAwareMethods(filter);
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;
                skipped = true;
            }
        }
    }
    if (!skipped) {
        return configurations;
    }
    List<String> result = new ArrayList<>(candidates.length);
    for (int i = 0; i < candidates.length; i++) {
        if (!skip[i]) {
            result.add(candidates[i]);
        }
    }
    if (logger.isTraceEnabled()) {
        int numberFiltered = configurations.size() - result.size();
        logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
    }
    return new ArrayList<>(result);
}

1)、先获取spring.factories中的AutoConfigurationImportFilter类型。

# 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

2)、遍历上面的三种类型,并且回调三种类型的BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware接口进行赋值。

3)、再结合spring-autoconfigure-metadata.properties中加载的具体类型调用match方法进行判定。

4)、组装过滤后的最终需要自动装配的类型,返回。

 

6)、发送AutoConfigurationImportEvent事件

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
    List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
    if (!listeners.isEmpty()) {
        AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
        for (AutoConfigurationImportListener listener : listeners) {
            invokeAwareMethods(listener);
            listener.onAutoConfigurationImportEvent(event);
        }
    }
}

    获取事件监听列表,遍历回调Aware接口,发送AutoConfigurationImportEvent 事件。

    监听列表也是自动装配的spring.factories中的AutoConfigurationImportListener类型。

7)、创建AutoConfigurationEntry对象返回

    根据需要自动装配的类型列表和需要排除的对象列表,创建AutoConfigurationEntry类型对象返回,为后续的selectImports回调做准备。

 

二、selectImports

@Override
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());
    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());
}

1)、从List<AutoConfigurationEntry> autoConfigurationEntries中,获取需要排除的HashSet

2)、从List<AutoConfigurationEntry> autoConfigurationEntries中,获取自动装配的List并转化为LinkedHashSet

3)、从自动装配列表中剔除需要排除的项

4)、将自动装配项进行排序,并且组装成DeferredImportSelector.Group.Entry类型,返回。

 

 

©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值