先从SpringBoot的核心注解@SpringBootApplication 看起
这个注解里面,最主要的就是@EnableAutoConfiguration,一看就是开启自动配置的,如此直白的名字也是我们要学习的
SpringBoot要开始骚操作了,我们进入@EnableAutoConfiguration一探究竟
首先看一下 @AutoConfigurationPackage 注解就是将主配置类(@SpringBootConfiguration标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器中。所以说,默认情况下主配置类包及子包以外的组件,Spring 容器是扫描不到的。
这里使用@Import注解,导入配置类,继续深入探究,看看AutoConfigurationImportSelector肚子里有什么墨水
在118行有个方法,来获取候选的配置:
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(Class<?> factoryType, @Nullable ClassLoader classLoader)方法,其中有两个参数,第一个参数指的是需要加载的类的类型,第二个参数是ClassLoader类加载。
继续深入探究loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
loadSpringFactories
- 从当前项目的类路径中获取所有 META-INF/spring.factories 这个文件下的信息。
- 将上面获取到的信息封装成一个 Map 返回。
- 从返回的 Map 中通过刚才传入的 EnableAutoConfiguration.class 参数,获取该 key 下的所有值。
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
META-INF/spring.factories 探究
我们来看一下 META-INF/spring.factories
这类文件是什么就不懵了。当然在很多第三方依赖中都会有这个文件,一般每导入一个第三方的依赖,除了本身的jar包以外,还会有一个 xxx-spring-boot-autoConfigure,这个就是第三方依赖自己编写的自动配置类。我们现在就以 spring-boot-autocongigure 这个依赖来说。
可以看到 EnableAutoConfiguration 下面有很多类,这些就是我们项目进行自动配置的类。
举个例子:打开org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration看一下
classpath下面必须要有CacheManager 这个Class文件
总结:
- 1、@EnableAutoConfiguration注解开启自动配置,并找到spring-boot-autoconfigure.jar包里的 META-INF/spring.factories 文件
- 2、通过factoryClassName找到 META-INF/spring.factories 文件对应的自动配置类列表
- 3、springboot上下文根据自动配置类里的 @Conditional 家族注解选择是否要加载这些配置
扩展:
通过以上描述,我们知道自动配置类是需要一定条件才能生效,可以通过启用debug = true属性,来查看自动配置报告