写于:2018-12-03 12:50:37 2020 进行更新
一、什么是自动化配置
在 Springboot 概述 中,通过简单的配置就实现了一个web应用,并且成功调用接口 localhost:8080/hello
。整个操作中,没有任何的配置,直接就启动了一个web应用,这得益于 spring boot 的自动化配置。
在 spring boot 存在很多的 xxxxAutoConfigration 结尾的配置类,而这些类都是相关的自动化配置类。其原理就是:springboot 提前帮我们写好了配置
,这也是 Spring 贯彻始终的思想 简化开发
,根据常规的开发方式,使用默认的配置,减少的代码量,提高了开发效率。为了提供灵活性高,当自动配置类无法满足我们需求时可以定制化。
Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added. For example, if HSQLDB is on your classpath, and you have not manually configured any database connection beans, then Spring Boot auto-configures an in-memory database.
You need to opt-in to auto-configuration by adding the @EnableAutoConfiguration or @SpringBootApplication annotations to one of your @Configuration classes.
大体翻译如下:
Spring Boot 会根据你添加的 jar 依赖尝试自动配置相关的配置。 而需要开启自动配置功能需要将
@EnableAutoConfiguration
或者@SpringBootApplication
添加到 应用的某个配置类上。
换句话说,只要在 spring 会扫描到的 class 文件加上 @EnableAutoConfiguration
或者 @SpringBootApplication
便能够开启自动配置功能,而自动配置功能,会根据依赖的 jar 包中提供的自动配置进行自动配置。
小贴士 通过查看
@SpringBootApplication
源码,
@EnableAutoConfiguration
public @interface SpringBootApplication {
......
}
得知
@SpringBootApplicaion
之所以能够支持自动配置功能,来自于其派生了@EnableAutoConfiguration
的能力。
二、自动化配置原理
根据官方给出的提示从:
@EnableAutoConfiguration
入手进行源码分析
step1、找到入口 @EnableAutoConfiguration
,代码如下
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 是否开启自动配置 开关
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
通过 @Import
能够知道,@EnableAutoConfiguration
加载的配置其实为 AutoConfigurationImportSelector
小贴士
在@EnableAutoConfiguration
中的spring.boot.enableautoconfiguration
是用来控制自动配置的开关。当不想使用自动化配置的时候,将spring.boot.enableautoconfiguration
设置为 false 即可关闭自动配置功能。 相关源码:AutoConfigurationImportSelector
public class AutoConfigurationImportSelector ......{
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
return getEnvironment().getProperty(
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY
,Boolean.class,true);
}
return true;
}
}
step2、聚焦 被 Import 的类 AutoConfigurationImportSelector
相关代码
下来看看 UML 中 ⑤ 、⑥ 的部分源码
public final class SpringFactoriesLoader {
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
// 自动配置时, factoryClassName = org.springframework.boot.autoconfigure.EnableAutoConfiguration
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
/** The location to look for factories.
* Can be present in multiple JAR files
*/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
......
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
......
}
}
上述源码功能讲解
- SpringFactoriesLoader#loadSpringFactories 会加载
META-INF/spring.factories
中配置的所有的 class 。 - SpringFactoriesLoader#loadFactoryNames 从加载的所有信息中过滤出在
META-INF/spring.factories
中 key =org.springframework.boot.autoconfigure.EnableAutoConfiguration
的所有 clas 文件。
下面配上一张 META-INF/spring.factories
部分信息图
接下来再来看看 ② 的相关代码
public class AutoConfigurationImportSelector ......{
protected AutoConfigurationEntry getAutoConfigurationEntry(){
......
// 获取到所有的自动配置 class
List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
// 过滤多余的自动配置 class
configurations = removeDuplicates(configurations);
// 根据 @EnableAutoConfiguraton 配置的 exclude 去除相关的 clas
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
}
上述源码大体功能讲解
获取到所有依赖 jar 中的 META-INF/spring.factories
中的 org.springframework.boot.autoconfigure.EnableAutoConfiguration
下的所有 自动配置 class 文件,然后去除重复的,被排除的一些 class 文件,最后得出本次启动需要加载的自动配置 class 列表。 class 列表最终由 ImportSelector#selectImports
,然后被初始化并注入到 IOC 容器中。
下面配上一张,最简 spring boot 应用需要加载的自动配置 class 列表
小贴士 TODO ImportSelector 接口文章(springframework)
三、总结
@EnableAutoConfiguration
会将 AutoConfigurationImportSelector
通过 @Import 加载到 Spring 上下文中。
AutoConfigurationImportSelector
会通过其他类的帮助从 META-INF/spring.factories
中获取到 org.springframework.boot.autoconfigure.EnableAutoConfiguration
配置下的所有 class 文件全路径列表,并根据相关规则过滤掉,如重复的,被排除的,最后得到本次应用启动需要被加载的所有自动配置类的 class 全路径列表。最后有 Spring 将其实例化并装配。
小贴士 Spring Boot 自动配置实现的前提是自动配置类在被引入依赖时未被 Spring 中的
@ComponentScan
扫描到。 需要注意的是,@SpringBootApplication
中的@ComponentScan
默认扫描的是Application.class
main class 下的包路径,如果引入的依赖 starter 的包路径和应用程序的扫描路径一直,则被引用的依赖包中的所有配置类都会被扫到 IOC 容器中,按需开启的注解式自动配置不再有效。