前几篇文章聊完了prepareContext方法,本文继续SpringApplication#run方法的下一行:refreshContext
这是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
再简单看下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源码的范畴,对每种类型的大致处理方式可以参考下图,这里不再详细展开
而这里的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以及它所属的配置类
回到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方法主要做了几件事情
DeferredImportSelectorGroupingHandler存储结构
全部注册完毕后,调用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容器中