zoukankan      html  css  js  c++  java
  • SpringBoot自动配置原理

    一、相关的几个注解

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
            @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {}
    1. 通常在启动类上使用 @SpringBootApplication
    2. 表明此类是配置类 + 启用自动配置 + 包扫描
    3. @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan

    二、@EnableAutoConfiguration

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

    简单AutoConfigurationImportSelector#selectImports流程

        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            // 可以命令行配置禁止自动配置 spring.boot.enableautoconfiguration
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            // 找到所有自动配置类, 过滤器处理 + 排除处理, AutoConfigurationEntry 封装了所有需要配置的和排除的
            AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
            // 得到需要配置的全部类
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
        
        
        protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return EMPTY_ENTRY;
            }
            AnnotationAttributes attributes = getAttributes(annotationMetadata);
            // 获取 META-INF/spring.factories EnableAutoConfiguration 配置列表
            List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
            // 去重(转Set再转List)
            configurations = removeDuplicates(configurations);
            // 要排除的自动配置类
            Set<String> exclusions = getExclusions(annotationMetadata, attributes);
            // 校验, 若配置了排除不在 configurations 中的类则抛出异常
            checkExcludedClasses(configurations, exclusions);
            // 排除
            configurations.removeAll(exclusions);
            // 过滤器列表, 过滤, META-INF/spring.factories 内的 AutoConfigurationImportFilter 配置
            // 过滤器处理后返回的列表可能有些类已经被排除了
            configurations = getConfigurationClassFilter().filter(configurations);
            // emm, META-INF/spring.factories 内的 AutoConfigurationImportListener 配置, 事件调用, configurations 是所有会自动配置的类
            fireAutoConfigurationImportEvents(configurations, exclusions);
            // 封装要自动配置的类 configurations + 排除的类 exclusions
            return new AutoConfigurationEntry(configurations, exclusions);
        }

    这里不太理解,过滤器过滤掉的配置类没有放入 exclusions 中,但是主动排除的放入了

    排除

    1. EnableAutoConfiguration 注解中的 exclude 属性和 excludeName 属性
    2. spring.autoconfigure.exclude 参数配置要排除的(命令行配置等)

    上面的 selectImports 实际不会被调用,因为 AutoConfigurationImportSelector 是 DeferredImportSelector 实现类,特殊处理的,看一些内部类

    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
            ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
            
            
        // 返回处理当前 DeferredImportSelector 的 Group 类型
        @Override
        public Class<? extends Group> getImportGroup() {
            return AutoConfigurationGroup.class;
        }
        
        // AutoConfigurationImportSelector 的内部类
        // 也继承了许多接口, 创建当前 Group 实例时也会回调这些 Aware 接口
        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;
    
            private AutoConfigurationMetadata autoConfigurationMetadata;
    
            // 接口回调 setter
    
    
            // 1. 会先调用 process
            //   --> 会使用一个 Group 实例处理它能处理的一系列 DeferredImportSelector 实例
            //     --> 每一个 DeferredImportSelector 实例都可以注入数据, 现在还未注入, 仅缓存起来
            @Override
            public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
                // 只处理 AutoConfigurationImportSelector
                // 说明这个 Group 仅处理这个类型的实例, 其他类型的 DeferredImportSelector 不处理
                Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
                        () -> String.format("Only %s implementations are supported, got %s",
                                AutoConfigurationImportSelector.class.getSimpleName(),
                                deferredImportSelector.getClass().getName()));
                // AutoConfigurationEntry 包装了要注入的自动配置类和排除了的配置类
                AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
                        .getAutoConfigurationEntry(annotationMetadata);
                this.autoConfigurationEntries.add(autoConfigurationEntry);
                // 遍历需要注入的配置类
                for (String importClassName : autoConfigurationEntry.getConfigurations()) {
                    // 配置类全类名 -> 导入此配置类的类的注解信息
                    this.entries.putIfAbsent(importClassName, annotationMetadata);
                }
                
                // 注意上面只是将要注入的数据缓存在了当前 Group 实例中
            }
    
            // 2. 调用它, 返回处理了的所有 DeferredImportSelector 实例要注入的数据
            @Override
            public Iterable<Entry> selectImports() {
                if (this.autoConfigurationEntries.isEmpty()) {
                    return Collections.emptyList();
                }
                // 移除的配置类 Set
                Set<String> allExclusions = this.autoConfigurationEntries.stream()
                        .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
                // 要注入的配置类 Set
                Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
                        .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
                        .collect(Collectors.toCollection(LinkedHashSet::new));
                // emm
                processedConfigurations.removeAll(allExclusions);
    
                // 排序
                return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
                        .map((importClassName) ->
                                // 导入此配置类的类的注解信息为 + 当前被自动注入的类
                                new Entry(this.entries.get(importClassName), importClassName))
                        .collect(Collectors.toList());
            }
    
            // ...
    
        }
        
    }

    三、总的涉及到的知识点

    1. Spring的SPI:META-INF/spring.factories
    2. @Import的处理
    3. DeferredImportSelector的处理
  • 相关阅读:
    STL unique使用问题
    自定义使用动态内存的类模板
    自定义类模板 重载<<遇到的问题
    [HDU 1882]--Strange Billboard(位运算+枚举)
    动态规划---最长上升子序列问题(O(nlogn),O(n^2))
    由结构体成员地址计算结构体地址——list_entry()原理详解
    不同意义的new和delete
    new[] 到底做了什么?
    lambda表达式与bind函数
    C++之可调用对象
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/15440556.html
Copyright © 2011-2022 走看看