SpringBoot 的核心作用
- 自动配置, 从而简化配置
@Import 基础
Spring refresh - invokeBeanFactoryPostProcessors - 解析 @Import
SpringBoot 2.2.6.RELEASE 自动配置入口
SpringBoot集成任意框架都是在Application上添加@EnableXxxxx注解, 自动装备也不例外, 使用@EnableAutoConfiguration注解来启动自动配置, 该注解在@SpringBootApplication注解内
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@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 {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
AutoConfigurationImportSelector
这里由@Import注解引入了一个AutoConfigurationImportSelector配置类, 该类实现了DeferredImportSelector接口, 且覆盖了getImportGroup方法, 返回了一个AutoConfigurationImportSelector.AutoConfigurationGroup类对象
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
// ...
public Class<? extends Group> getImportGroup() {
return AutoConfigurationImportSelector.AutoConfigurationGroup.class;
}
// ...
}
AutoConfigurationGroup.process
AutoConfigurationImportSelector有一个内部类AutoConfigurationGroup实现了Group接口, SpringBoot启动时调用其process方法, 内部调用DeferredImportSelector的getAutoConfigurationEntry方法, 内部调用SpringFactoriesLoader.loadFactoryNames方法从所有jar包的"META-INF/spring.factories"文件内读取key为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的自动配置的Bean的全类名
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 获取要自动配置的Bean的列表, AutoConfigurationEntry, 内部有要配置的 List<String> configurations 和 要排除的 Set<String>
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
AutoConfigurationImportSelector.getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取使用@EnableAutoConfiguration注解指定排除的自动配置类 exclude 和 excludeName
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 从所有jar中找 "META-INF/spring.factories", 并从中拿到key为 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的所有配置项, 不仅是 spring 自带的 spring-boot-autoconfigure, 还有 dubbo-spring-boot-autoconfigure, mybatis-spring-boot-autoconfigure, pagehelper-spring-boot-autoconfigure 等等jar包中也有这个key, 所有涉及的自动配置类都会被找到
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 移除重复的配置项
configurations = removeDuplicates(configurations);
// 获取到要排除的配置项
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查是否有无效的排除项
checkExcludedClasses(configurations, exclusions);
// 自动配置项中移除排除项
configurations.removeAll(exclusions);
// 根据各种@Condition条件, 把不需要自动配置的配置类过滤掉
// # 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
configurations = filter(configurations, autoConfigurationMetadata);
// 触发 @Import 的监听类 AutoConfigurationImportListener 的 onAutoConfigurationImportEvent 方法
// # Auto Configuration Import Listeners
// org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
// org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
从 META-INF/spring.factories 中找到指定 key 的 value
// 这两个方法, 从所有jar中的 "META-INF/spring.factories" 中找factoryType指定的key对应的类
SpringFactoriesLoader.loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader)
SpringFactoriesLoader.loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader)
AutoConfigurationGroup.selectImports
调用完AutoConfigurationGroup的process方法后, 调用其selectImports方法, 将所有已经处理过的autoConfigurationEntries中的自动配置项重新排除一遍所有过滤项, 然后包装成一个个Entry并排序
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);
// 主要是根据 Ordered, @Order, @AutoConfigureBefore, @AutoConfigureAfter 等给自动配置类做排序
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}