Spring Boot自动装配原理(一)

@EnableAutoConfiguration读取候选装配组件

参考@EnableAutoConfiguration注解定义,在Import中导入AutoConfigurationImportSelector类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
  ...
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                configurations = this.removeDuplicates(configurations);
                configurations = this.sort(configurations, autoConfigurationMetadata);
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return StringUtils.toStringArray(configurations);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }
  ...
}

其中, List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);作为Importselect返回的对象,返回的是导入类名集合,所以该对象为自动装配的候选类集合

@EnableAutoConfigurations读取候选装配组件

该方法调用为SpringFactoriesLoader.loadFactoryNames

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}

进入SpringFactoriesLoader

public abstract class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    ...
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
                        result.addAll((String)entry.getKey(), factoryClassNames);
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var9) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
            }
        }
    }
    ...
}

(1) 搜索指定ClassLoader下所有META-INF/spring.factories的资源内容

(2) 将一个或多个META-INF/spring.factories资源作为Properties文件读取,合并为一个key为接口的全类名,Value是全类名实现类的列表的Map,作为loadSpringFactories方法的返回值

由于@EnableAutoConfiguration配置可能存在自动装配组件类名重复定义的情况,当获取所有候选类名集合后,会执行removeDuplicates方法,利用set的不能重复特性达到去重

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

@EnableAutoConfigution排除自动装配组件

当getExclutions方法执行后,程序将获得一个自动装配排除名单

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    Set<String> excluded = new LinkedHashSet();
    excluded.addAll(this.asList(attributes, "exclude"));
    excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
    excluded.addAll(this.getExcludeAutoConfigurationsProperty());
    return excluded;
}
private List<String> getExcludeAutoConfigurationsProperty() {
    if (this.getEnvironment() instanceof ConfigurableEnvironment) {
        Binder binder = Binder.get(this.getEnvironment());
        return (List)binder.bind("spring.autoconfigure.exclude", String[].class).map(Arrays::asList).orElse(Collections.emptyList());
    } else {
        String[] excludes = (String[])this.getEnvironment().getProperty("spring.autoconfigure.exclude", String[].class);
        return excludes == null ? Collections.emptyList() : Arrays.asList(excludes);
    }
}

该方法将注解属性exclude和excludeName以及spring.autoconfigure.exclude配置累加到集合excluded

检查集合类名是否合法

private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
    List<String> invalidExcludes = new ArrayList(exclusions.size());
    Iterator var4 = exclusions.iterator();

    while(var4.hasNext()) {
        String exclusion = (String)var4.next();
        if (ClassUtils.isPresent(exclusion, this.getClass().getClassLoader()) && !configurations.contains(exclusion)) {
            invalidExcludes.add(exclusion);
        }
    }

    if (!invalidExcludes.isEmpty()) {
        this.handleInvalidExcludes(invalidExcludes);
    }

}

从自动装配的候选名单中移除

configurations.removeAll(exclusions);

@EnableAutoConfiguration过滤自动装配组件

移除排除类名单后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;
    Iterator var8 = this.getAutoConfigurationImportFilters().iterator();

    while(var8.hasNext()) {
        AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var8.next();
        this.invokeAwareMethods(filter);
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);

        for(int i = 0; i < match.length; ++i) {
            if (!match[i]) {
                skip[i] = true;
                skipped = true;
            }
        }
    }

    if (!skipped) {
        return configurations;
    } else {
        List<String> result = new ArrayList(candidates.length);

        int numberFiltered;
        for(numberFiltered = 0; numberFiltered < candidates.length; ++numberFiltered) {
            if (!skip[numberFiltered]) {
                result.add(candidates[numberFiltered]);
            }
        }

        if (logger.isTraceEnabled()) {
            numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
        }

        return new ArrayList(result);
    }
}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
    return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}

当前方法的作用是过滤META-INF/spring.factories资源中那些当前ClassLoader不存在的class

AutoConfigurationMetadata来源

public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
    return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
}

执行完排除名单后,该方法再次过滤了候选自动装配Class集合中Class不存在的成员

@EnableAutoConfiguration自动装配事件

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
    List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
    if (!listeners.isEmpty()) {
        AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
        Iterator var5 = listeners.iterator();

        while(var5.hasNext()) {
            AutoConfigurationImportListener listener = (AutoConfigurationImportListener)var5.next();
            this.invokeAwareMethods(listener);
            listener.onAutoConfigurationImportEvent(event);
        }
    }

}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
    return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
}

spring boot自1.5版本引入AutoConfigurationImportListener,为自定义的Java ListenerEvent实现,仅监听AutoConfigurationImportEvent。实例同样被SpringFactoriesLoader加载

通过自定义listener验证

public class MyListener implements AutoConfigurationImportListener {
    @Override
    public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
        //获取当前classloader
        ClassLoader classLoader = event.getClass().getClassLoader();
        //获取候选装配名单
        List<String> candi = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);
        //实际的装配名单
        List<String> configs = event.getCandidateConfigurations();
        //排除的装配名单
        Set<String> exc = event.getExclusions();

        System.out.printf("候选装配数量:%s,实际数量:%s,排除数量:%s",candi.size(),configs.size(),exc.size());
    }
}

新建spring.factories

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\com.wang.springbatch.autoconfiguration.lister.MyListener

引导类

@EnableAutoConfiguration(exclude = SpringApplicationAdminJmxAutoConfiguration.class)
public class EurekaClientApplication {

    public static void main(String[] args) {
//        SpringApplication.run(EurekaClientApplication.class, args);

        new SpringApplicationBuilder(EurekaClientApplication.class)
                .web(WebApplicationType.NONE)
                .run(args)
                .close();
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容