002-Spring boot 自动配置相关分析

自动配置 @EnableAutoConfiguration

开启自动配置

在Spring 启动类上的 @SpringBootApplication 中有 @EnableAutoConfiguration

读取配置

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
	AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
	return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

也就是导入了 AutoConfigurationImportSelector
我们在 Spring 时代知道这个类会返回配置类的全类名
也就是在 selectImports 方法中返回了自动配置的相关类的全类名的集合
Spring boot 自动装配的配置类有144个
如果一个一个写,那代码就太长了
所以Spring 就把这些配置类都配置在一个文件中

但是如果你debug到 selectImports() 里会发现并没有进这个方法
是因为 DeferredImportSelector 这个接口 他其实是进入的 getImportGroup()

public Class<? extends Group> getImportGroup() {
	return AutoConfigurationGroup.class;
}

最终调用的是 org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process

//最终还是会调用 deferredImportSelector
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.deferredImportSelector(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
	this.entries.putIfAbsent(importClassName, annotationMetadata);
} 

//后续排序后返回
//排序规则:
1.@AutoConfigureOrder 配置的顺序
2.@AutoConfigureAfter@AutoConfigureBefore
getAutoConfigurationEntry(annotationMetadata)//读取 @EnableAutoConfiguration 的配置信息
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//读取所有的 META-INF/spring.factories 文件中配置的配置类
//读取所有的 @AutoConfiguration 注解的配置类
//这里会把 classLoader里所有的META-INF/spring.factories文件都读出来汇总
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//有序去重 这一步很好玩 平时也可以用 
//new ArrayList<>(new LinkedHashSet<>(list));
configurations = removeDuplicates(configurations);

//读取 注解中配置的排除类 排除掉
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);

//这一步 是提前过滤一些肯定不能行的配置类
//具体怎么做的下边分析
configurations = getConfigurationClassFilter().filter(configurations);
//触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);

META-INF/spring.factories 文件示例:
在这里插入图片描述

//文件内容 接口 = 类名列表,多个用“,”隔开

文件解析方法 loadSpringFactories():

//读取classLoader中所有的文件
Map<String, List<String>> result = new HashMap<>();
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
	URL url = urls.nextElement();
	//读取并创建资源
	UrlResource resource = new UrlResource(url);
	//解析成 properties 其实就是个 Map
	Properties properties = PropertiesLoaderUtils.loadProperties(resource);
	for (Map.Entry<?, ?> entry : properties.entrySet()) {
		String factoryTypeName = ((String) entry.getKey()).trim();
		// 按 ‘,’ 分割
		String[] factoryImplementationNames =
				StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
		for (String factoryImplementationName : factoryImplementationNames) {
			//这个就是常用的 map的value是list
			result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
					.add(factoryImplementationName.trim());
		}
	}
}
return result;

提前过滤

getConfigurationClassFilter().filter(configurations):

getConfigurationClassFilter():
//读取到三个
//OnBeanCondition
//OnClassCondition
//OnWebApplicationCondition
filters = SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
for (AutoConfigurationImportFilter filter : filters) {
	invokeAwareMethods(filter);
}
//这里再创建 ConfigurationClassFilter 的时候就读取了预处理的配置文件
//META-INF/spring-autoconfigure-metadata.properties
//这个配置类里边已经配好类名和提前过滤配置的内容
return this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);

//根据配置类中的内容提前过滤一下
//OnBeanCondition :没有配置类型的Bean定义就别解析了
//OnClassCondition :没有配置的类文件就别解析了
//OnWebApplicationCondition :不是配置的上下文类型就别解析了
//这样一来就快速的过滤掉一些肯定不能创建的配置类
ConfigurationClassFilter.filter(configurations):

META-INF/spring-autoconfigure-metadata.properties 文件内容示例:
在这里插入图片描述

自动配置配置包 @AutoConfigurationPackage

这个注解是配置自动装配所作用的包的对象
在实际工作中有的时候需要把一个老项目代码迁移到新的项目中
为了避免出现大量改动可以把包平移到新的项目中
然后在新项目中配置扫描老项目的包名
有的时候会发现Bean注册没问题,但是一些自动装配扫描的Bean就没有注册
比如 ES 自动装配的时候就会基于这个 package 来扫描

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值