SpringBoot自动配置原理简解一
我们从一个SpringBoot项目中的主方法上的注解讲起。这个注解就是非常重要的@SpringBootApplication.
SpringBootApplication注解
首先看一下SpringBootApplication类的定义。
@EnableAutoConfiguration
public @interface SpringBootApplication {
SpringBootApplication 类上面也有一个很重要的注解@EnableAutoConfiguration
EnableAutoConfiguration注解
我们再来看看这个注解类的定义
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
这个类的作用就是开启自动配置功能。同样的,这个类上还是有一个很重要的注解@Import,这是为了导入AutoConfigurationImportSelector类。
AutoConfigurationImportSelector类
我们继续查看它的定义和部分方法
public class AutoConfigurationImportSelector implements...{
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
该方法就是给容器导入一些默认配置好的组件名称。
我们看其具体实现。在这里挑一些重要的方法简单讲述一下,详细的大家可以打开源码对照的看。
getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata)里,调用List configurations = getCandidateConfigurations(annotationMetadata, attributes);我们着重看一下getCandidateConfigurations方法。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
在这个方法里,要分几个步骤来讲解。
- getSpringFactoriesLoaderFactoryClass() 的返回结果是EnableAutoConfiguration.class;
- getBeanClassLoader() 是当前的类加载器;
- 而后我们继续查看SpringFactoriesLoader.loadFactoryNames方法;
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
- 上述方法里又得继续细细来看,同学们可不能着急啊,code得一行行看才能清楚原理。
- loadSpringFactories方法简述
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); ...
- 此方法的主要作用是获取项目中所有META-INF/spring.factories文件中的键值。
- spring.factories文件中的部分内容如下:
# Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener # 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 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
- 紧接着的 .getOrDefault(factoryClassName, Collections.emptyList()) 方法里就是得到factoryClassName对应的集合的值。
- 而这里的factoryClassName就是我们loadFactoryNames方法的第一个参数EnableAutoConfiguration.class对应的类路径。
- 最后的结果就显而易见就是得到了META-INF/spring.factories里EnableAutoConfiguration的值。部分值如下:
# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\ org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
- loadSpringFactories方法简述
6.因此,SpringBoot会把配置文件中所有xxxAutoConfiguration结尾的类全部自动配置加载到容器中。
结束语
至此,SpringBoot中在没有手动配置某些文件的情况下一些功能是如何自动生效的原理就大概讲述了一下。本文是个人见解,如有差错还请同学们留言指正。
下节有时间的话,我会挑一些具体的功能是如何自动配置生效的,如WebMvcAutoConfiguration等。