【Spring Boot】自动装配
【引言】
Spring Boot 应用之所以能够很快的集成一些东西,原因在于它的自动装配功能。
【描述】
在Spring Boot 官方文档中,“16. Auto-configuration”介绍的便是它的自动装配特性,描述如下:
Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added.
按照该说明,自动装配是存在前提的,它取决于开发人员在应用的Class Path下添加的JAR文件依赖,同时其自动装配的实体并非一定装载。
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.
比如说,当HSQLDB存在于应用的Class Path时,开发人员不需要手动配置数据库连接的Beans,而是由Spring Boot自动装配一个内存型的数据库。
Spring Boot自动装配的对象是Spring Bean,所以不需要人工干预。比如通过XML配置文件或Java编码等方式组装Bean。
【注解】
Spring Boot 应用的启动类核心注解@SpringBootApplication ,是一个组合注解,包含以下三个注解:
- @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
- @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
- @ComponentScan:Spring组件扫描。
其中,@EnableAutoConfiguration实现了spring boot应用的自动装配。
在@EnableAutoConfiguration注解上,会引入AutoConfigurationImportSelector类,@Import({AutoConfigurationImportSelector.class}),在AutoConfigurationImportSelector类中,完成了自动装配功能。
【源码】
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重复配置
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);
}
}
getCandidateConfigurations(annotationMetadata, attributes)方法为获取自动装配的候选类集合,而此方法实现如下:
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,ClassLoader)方法:
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 factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
SpringFactoriesLoader是Spring Framework工厂机制的加载器,loadFactoryNames(Class,ClassLoader)方法加载原理如下:
- 搜索指定ClassLoader下所有的META-INF/spring.factories资源内容,文件内容截取如下:
- 将一个或多个META-INF/spring.factories资源内容作为Properties文件读取,合并为一个Key为接口全类名,Value是实现类全类名列表的Map,作为loadSpringFactories(ClassLoader)方法的返回值。
- 再从上一步返回的Map中查找并返回方法指定类名所映射的实现类全类名列表。
【总结】
AutoConfigurationImportSelector读取自动装配Class的流程如下:
- 通过SpringFactoriesLoader的loadSpringFactories方法读取所有资源中@EnableAutoConfiguration所关联的自动装配Class集合。
- 读取当前配置类所标注@EnableAutoConfiguration属性exclude和excludeName,并与spring.autoconfigure.exclude配置属性合并为自动装配Class排除集合。
- 检查自动装配Class集合是否合法。
- 排除候选自动装配Class集合中Class不存在的成员。
- 再次过滤候选自动装配Class集合中不存在的成员。
还没有评论,来说两句吧...