SpringBoot源码解析(十八)自动配置

前几篇文章聊完了prepareContext方法,本文继续SpringApplication#run方法的下一行:refreshContext
SpringBoot源码解析(十八)自动配置_第1张图片
这是Spring容器启动过程最重要的一个步骤,所有的扫描、解析、注入等等都在这里面完成的,当然本文依然是把焦点聚集在SpringBoot上,它的自动配置,也是在容器refresh的过程中执行的

作为SpringBoot项目,启动类会加一个注解@SpringBootApplication,我们从这个注解开始入手,看它都做了哪些初始化,怎么整合到容器的启动流程并完成自动配置

首先看下这个注解的内部结构

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

其中组合了一个@EnableAutoConfiguration注解,顾名思义,它会用来完成自动配置,再看下它的定义

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

这个注解通过@Import导入了一个类AutoConfigurationImportSelector,我们看下这个类的继承结构,它实现了DeferredImportSelector接口,这个接口扩展自ImportSelector
SpringBoot源码解析(十八)自动配置_第2张图片
再简单看下DeferredImportSelector的定义,它有一个getImportGroup方法,并且有一个内部接口Group,
这个Group用于对Selector分组,不同的Group可以实现不同的配置方式,SpringBoot导入的AutoConfigurationImportSelector内部也会定义一个自己的Group,通过其getImportGroup方法返回,我们后续会看到

public interface DeferredImportSelector extends ImportSelector {
    @Nullable
    default Class<? extends DeferredImportSelector.Group> getImportGroup() {
        return null;
    }

    public interface Group {
		......
		......
	}
}

Spring对于@Import导入类的处理,一般有三种类型,实现ImportSelector接口、实现ImportBeanDefinitionRegistrar接口,以及普通类,这个算是Spring源码的范畴,对每种类型的大致处理方式可以参考下图,这里不再详细展开
SpringBoot源码解析(十八)自动配置_第3张图片
而这里的DeferredImportSelector类型虽然扩展自ImportSelector,但是它比较特殊,它的执行方式不同于ImportSelector,会延迟执行,等其它@Import全部完成后才会工作,而且调用的方法和导入ImportSelector也不一样

具体处理@Import的位置是ConfigurationClassParser的parse方法,调用栈就不详细跟了,是从ConfigurationClassPostProcessor的postProcessorBeanDefinitionRegistry方法中触发的,这个类是Spirng初始化流程非常关键的一个类,我们前面的文章也提到过几次,看下这个parse方法

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        Iterator var2 = configCandidates.iterator();

        while(var2.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
            BeanDefinition bd = holder.getBeanDefinition();

            try {
                if (bd instanceof AnnotatedBeanDefinition) {
                    this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
                } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
                    this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
                } else {
                    this.parse(bd.getBeanClassName(), holder.getBeanName());
                }
            } catch (BeanDefinitionStoreException var6) {
                throw var6;
            } catch (Throwable var7) {
                throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
            }
        }

        this.deferredImportSelectorHandler.process();
    }

在try模块中,我们通过注解@Import导入的类,会走第一个分支,调用this.parse开始解析@Import的内容,完成相关类的导入
在方法的最后,又调用了this.deferredImportSelectorHandler.process(),看名字它肯定跟我们上面导入的DeferredImportSelector有关

实际上在调用this.parse的时候,如果发现当前类实现了DeferredImportSelector接口,并不会真正处理,而是把它存储到一个集合中,最后等其它类执行完毕后,再通过这个集合,处理DeferredImportSelector的导入

具体看下这个过程,parse最终会调用当前类的processImports方法

    private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, boolean checkForCircularImports) {
        ......
        ......
        if (candidate.isAssignable(ImportSelector.class)) {
              candidateClass = candidate.loadClass();
              ImportSelector selector = (ImportSelector)BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
              ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
              if (selector instanceof DeferredImportSelector) {
                  this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector)selector);
              } else {
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                  Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames);
                  this.processImports(configClass, currentSourceClass, importSourceClasses, false);
              }
         } 
         ......
         ......
    }

在处理ImportSelector的分支中,如果发现导入的类是DeferredImportSelector类型,则调用 this.deferredImportSelectorHandler.handle方法,将其封装成一个Holder,存储到List中

    private class DeferredImportSelectorHandler {
        @Nullable
        private List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImportSelectors;

        private DeferredImportSelectorHandler() {
            this.deferredImportSelectors = new ArrayList();
        }

        public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
            ConfigurationClassParser.DeferredImportSelectorHolder holder = new ConfigurationClassParser.DeferredImportSelectorHolder(configClass, importSelector);
            ......
            this.deferredImportSelectors.add(holder);
            ......
        }
        
        public void process() {
            List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
            this.deferredImportSelectors = null;

            try {
                if (deferredImports != null) {
                    ConfigurationClassParser.DeferredImportSelectorGroupingHandler handler = ConfigurationClassParser.this.new DeferredImportSelectorGroupingHandler();
                    deferredImports.sort(ConfigurationClassParser.DEFERRED_IMPORT_COMPARATOR);
                    deferredImports.forEach(handler::register);
                    handler.processGroupImports();
                }
            } finally {
                this.deferredImportSelectors = new ArrayList();
            }

        }
    }    

DeferredImportSelectorHandler 内部相当于存储了一个Holder列表,每个Hodler中存储了DeferredImportSelector以及它所属的配置类
SpringBoot源码解析(十八)自动配置_第4张图片

回到parse方法,其它的导入类执行完毕后,调用deferredImportSelectorHandler.process方法

	......
	......
    public void process() {
        List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;

        try {
            if (deferredImports != null) {
                ConfigurationClassParser.DeferredImportSelectorGroupingHandler handler = ConfigurationClassParser.this.new DeferredImportSelectorGroupingHandler();
                deferredImports.sort(ConfigurationClassParser.DEFERRED_IMPORT_COMPARATOR);
                deferredImports.forEach(handler::register);
                handler.processGroupImports();
            }
        } finally {
            this.deferredImportSelectors = new ArrayList();
        }

    }
    ......
    ......

在这个方法中,先创建了一个DeferredImportSelectorGroupingHandler,然后循环所有的Holder,传递给它的register方法

    public void register(ConfigurationClassParser.DeferredImportSelectorHolder deferredImport) {
        Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
        ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)this.groupings.computeIfAbsent(group != null ? group : deferredImport, (key) -> {
            return new ConfigurationClassParser.DeferredImportSelectorGrouping(this.createGroup(group));
        });
        grouping.add(deferredImport);
        this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass());
    }

register方法主要做了几件事情

  1. 获取DeferredImportSelector的Group,每个DeferredImportSelector会实现一个getImportGroup方法,返回自己所属的Group
  2. 将Group添加到groupingHandler的Map中,value为封装后 的Grouping,包含Group和对应的Hodler列表
  3. 将配置类元信息添加到GroupingHandler中(key为配置类的metaData,value为配置类)

DeferredImportSelectorGroupingHandler存储结构
SpringBoot源码解析(十八)自动配置_第5张图片

全部注册完毕后,调用handler.processGroupImports

    public void processGroupImports() {
        Iterator var1 = this.groupings.values().iterator();

        while(var1.hasNext()) {
            ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)var1.next();
            grouping.getImports().forEach((entry) -> {
                ConfigurationClass configurationClass = (ConfigurationClass)this.configurationClasses.get(entry.getMetadata());

                try {
                    ConfigurationClassParser.this.processImports(configurationClass, ConfigurationClassParser.this.asSourceClass(configurationClass), ConfigurationClassParser.this.asSourceClasses(entry.getImportClassName()), false);
                } catch (BeanDefinitionStoreException var4) {
                    throw var4;
                } catch (Throwable var5) {
                    throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", var5);
                }
            });
        }

    }

首先循环内部的grouping,调用getImports方法,对返回的结果再进行forEach循环处理,先看getImports方法

    public Iterable<Entry> getImports() {
        Iterator var1 = this.deferredImports.iterator();

        while(var1.hasNext()) {
            ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
            this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
        }
        return this.group.selectImports();
    }

这个方法又会循环内部的Holder列表,调用this.group.process方法,这里Group的具体实现是AutoConfigurationGroup,它是SpringBoot导入的AutoConfigurationImportSelector的内部类,看其process方法

    public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
        Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
            return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
        });
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(this.getAutoConfigurationMetadata(), annotationMetadata);
        this.autoConfigurationEntries.add(autoConfigurationEntry);
        Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();

        while(var4.hasNext()) {
            String importClassName = (String)var4.next();
            this.entries.putIfAbsent(importClassName, annotationMetadata);
        }

    }

这个方法会寻找所有需要自动配置的类,进入getAutoConfigurationEntry方法

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

首先判断是否开启了自动配置,如果spring.boot.enableautoconfiguration属性设置为false,就返回一个空结果,默认是开启的

    protected boolean isEnabled(AnnotationMetadata metadata) {
        return this.getClass() == AutoConfigurationImportSelector.class ? (Boolean)this.getEnvironment().getProperty("spring.boot.enableautoconfiguration", Boolean.class, true) : true;
    }

然后进入自动配置流程,首先调用getCandidateConfigurations方法到META-INF/spring.factories中加载需要自动配置的列表

    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.loadFactoryNames方法,这里它要找的类型,通过方法this.getSpringFactoriesLoaderFactoryClass()返回,即EnableAutoConfiguration类型

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

找到自动配置的列表后,需要做一个过滤,只留下符合当前环境,真正需要完成自动配置的类
过滤流程分两个步骤,第一步先筛除我们手动配置的过滤项,第二步再根据系统配置的过滤器来过滤,先看第一步,调用getExclusions方法

    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;
    }

首先根据配置类上的exclude和excludeName来过滤,然后调用getExcludeAutoConfigurationsProperty方法,看我们是否通过配置属性spring.autoconfigure.exclude来指定过滤项

    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 ? Arrays.asList(excludes) : Collections.emptyList();
        }
    }

处理完手动配置的过滤项后,回到getAutoConfigurationEntry方法,继续调用filter方法完成系统过滤

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;
                    candidates[i] = null;
                    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);
        }
    }

该方法先通过getAutoConfigurationImportFilters加载系统配置的过滤器,也就是到META-INF/spring.factories中找AutoConfigurationImportFilter

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

最终在spring-boot-autoconfigure包下找到3个,这几个名字我们应该很熟悉了,在自动配置的类中,会添加一些条件注解,比如@ConditionalOnBean 等,根据当前容器中是否存在某个Bean,类决定当前类是否装配到容器中

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

最后通过这几个Filter,筛选出最终需要装配到容器中的类

这个遍历的过程结束后,回到getImports方法,调用最后一行this.group.selectImports()

        public Iterable<Entry> getImports() {
            Iterator var1 = this.deferredImports.iterator();

            while(var1.hasNext()) {
                ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var1.next();
                this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector());
            }

            return this.group.selectImports();
        }

具体实现同样在AutoConfigurationImportSelector中,它会将需要自动配置的类封装成一个Entry返回

    public Iterable<Entry> selectImports() {
        if (this.autoConfigurationEntries.isEmpty()) {
            return Collections.emptyList();
        } else {
            Set<String> allExclusions = (Set)this.autoConfigurationEntries.stream().map(AutoConfigurationImportSelector.AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
            Set<String> processedConfigurations = (Set)this.autoConfigurationEntries.stream().map(AutoConfigurationImportSelector.AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));
            processedConfigurations.removeAll(allExclusions);
            return (Iterable)this.sortAutoConfigurations(processedConfigurations, this.getAutoConfigurationMetadata()).stream().map((importClassName) -> {
                return new Entry((AnnotationMetadata)this.entries.get(importClassName), importClassName);
            }).collect(Collectors.toList());
         }
    }

回到processGroupImports方法,遍历上一步封装的Entry,调用processImports方法,完成类的导入,这个过程跟Spring处理@Import是完全一样的

    public void processGroupImports() {
        Iterator var1 = this.groupings.values().iterator();

        while(var1.hasNext()) {
            ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)var1.next();
            grouping.getImports().forEach((entry) -> {
                ConfigurationClass configurationClass = (ConfigurationClass)this.configurationClasses.get(entry.getMetadata());

                try {
                    ConfigurationClassParser.this.processImports(configurationClass, ConfigurationClassParser.this.asSourceClass(configurationClass), ConfigurationClassParser.this.asSourceClasses(entry.getImportClassName()), false);
                } catch (BeanDefinitionStoreException var4) {
                    throw var4;
                } catch (Throwable var5) {
                    throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", var5);
                }
            });
        }
    }

至此,SpringBoot就完成了自动配置,我们常见的各种starter,其实就是在其META-INF/spring.factories中配置自定义的EnableAutoConfiguration,在对应的类中添加条件注解,然后通过上面的一些列流程,加载到了Spring容器中

你可能感兴趣的:(springboot源码,spring,boot,java)