SpringBoot自动配置源码深入刨析讲解

2023-02-23 0 2,337

目录

自动配置底层源码分析

本次springboot源码来自2.6.6版本。
@EnableAutoConfiguration源码解析
在springboot中,当我们引入某个依赖,就可以直接使用依赖里面的类进行自动注入,不需要像ssm框架那样在xml文件中配置各种bean,然后进行关联。像这样我们称之为自动配置。那么自动配置到底配了什么?
SpringBoot中的自动配置,更多的是配置各种Bean,同时对于端口号这些配置,一些特定属性SpringBoot也是会提供一种默认值的,也相当于一种自动配置。
那SpringBoot是如何自动的帮助我们来配置这些Bean的呢?并且如果某些Bean程序员自己也配置了,那SpringBoot是如何进行选择的呢?
在springboot启动类中有@SpringBootApplication注解,该注解包含了@EnableAutoConfiguration
SpringBoot自动配置源码深入刨析讲解
SpringBoot自动配置源码深入刨析讲解
而@EnableAutoConfiguration的作用就是导入AutoConfigurationImportSelector.class这个类。在spring中的配置类源码分析中,分析过@Import导入的类会当成配置类来解析,并且如果这个配置类是实现了DeferredImportSelector接口,就会调用selectImports方法。这部分属于spring源码的知识不在赘述。
SpringBoot自动配置源码深入刨析讲解
有上述类关系图中可以看出,会调用AutoConfigurationImportSelector的selectImports方法
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 会在所有@Configuration都解析完了之后才执行
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 获取自动配置类(spring.factories中所导入的)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

而selectImports的核心代码在于getAutoConfigurationEntry(annotationMetadata)。接下来一步步分析这个方法
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取@EnableAutoConfiguration的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取spring.factories中所有的AutoConfiguration
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去重(也就是按类名去重)
configurations = removeDuplicates(configurations);
// 获取需要排除的AutoConfiguration,可以通过@EnableAutoConfiguration注解的exclude属性,或者spring.autoconfigure.exclude来配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 排除
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 获取spring.factories中的AutoConfigurationImportFilter对AutoConfiguration进行过滤
// 默认会拿到OnBeanCondition、OnClassCondition、OnWebApplicationCondition
// 这三个会去判断上面的AutoConfiguration是否符合它们自身所要求的条件,不符合的会过滤掉,表示不会进行解析了
// 会利用spring-autoconfigure-metadata.properties中的配置来进行过滤
// spring-autoconfigure-metadata.properties文件中的内容是利用Java中的AbstractProcessor技术在编译时生成出来的
configurations = getConfigurationClassFilter().filter(configurations);
// configurations表示合格的,exclusions表示被排除的,把它们记录在ConditionEvaluationReportAutoConfigurationImportListener中
fireAutoConfigurationImportEvents(configurations, exclusions);

// 最后返回的AutoConfiguration都是符合条件的
return new AutoConfigurationEntry(configurations, exclusions);
}

首先执行 AnnotationAttributes attributes = getAttributes(annotationMetadata);拿到@EnableAutoConfiguration的属性封装成AnnotationAttributes 。List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)加载自动配置类。看看源码是怎么获取的
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//核心方法 传入EnableAutoConfiguration类和类加载器
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;
}
//返回EnableAutoConfiguration
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
//获取类加载器
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
//这个name就是EnableAutoConfiguration
String factoryTypeName = factoryType.getName();
//这部分代码具体的去加载自动配置类
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());这部分代码如下图,
SpringBoot自动配置源码深入刨析讲解
通过类加载去加载资源,其中红色部分的静态变量就是 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";。也就是说类加载器去META-INF/spring.factories里面的资源
.getOrDefault(factoryTypeName, Collections.emptyList());这部分就是根据factoryTypeName也就是EnableAutoConfiguration。获取EnableAutoConfiguration的值封装成List<String>
SpringBoot自动配置源码深入刨析讲解
到此就获取到了所有自动配置类。那么List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);这个方法就结束了。接着执行configurations = removeDuplicates(configurations);这部分主要用去重
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}

接着执行Set<String> exclusions = getExclusions(annotationMetadata, attributes);这个方法主要是把需要排除的配置类的类名放入到集合当中。
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
//获取EnableAutoConfiguration注解的exclude属性的值 添加到排除集合当中
excluded.addAll(asList(attributes, \"exclude\"));
//获取EnableAutoConfiguration注解的excludeName属性的值 添加到排除集合当中
excluded.addAll(Arrays.asList(attributes.getStringArray(\"excludeName\")));
//从配置文件中获取spring.autoconfigure.exclude 的值 添加到排除集合中
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}

往下执行checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions); 从之前获取到的自动配置类的类名中排除掉那些需要被排除了类名。
接着执行configurations = getConfigurationClassFilter().filter(configurations);。将排除后的自动配置类的名称作为入参,这部分代码是提前判断一些条件进行过滤掉不需要加载的自动配置类
private ConfigurationClassFilter getConfigurationClassFilter() {
if (this.configurationClassFilter == null) {
//获取自动配置类的过滤器
List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
for (AutoConfigurationImportFilter filter : filters) {
invokeAwareMethods(filter);
}
//将所有过滤器封装成 ConfigurationClassFilter
this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
}
return this.configurationClassFilter;
}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
//底层从 META-INF/spring.factories中加载 AutoConfigurationImportFilter的值
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}

上面获取到的过滤器就是这部分
SpringBoot自动配置源码深入刨析讲解
获取到所有过滤器后通过filter(configurations);进行过滤
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
//把自动配置类的名称封装成数组
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
// 逐个利用AutoConfigurationImportFilter来判断所有的自动配置类的条件是否匹配,匹配结果存在match数组中
// 先利用OnBeanCondition进行过滤
// 再利用OnClassCondition进行过滤
// 再利用OnWebApplicationCondition进行过滤
for (AutoConfigurationImportFilter filter : this.filters) {
//把过滤的结果 放入到boolean的数组中
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
//如果匹配失败 排除掉该自动配置类
candidates[i] = null;
skipped = true;
}
}
}
// 全部都匹配
if (!skipped) {
return configurations;
}
// 把匹配的记录在result集合中,最后返回
List<String> result = new ArrayList<>(candidates.length);
for (String candidate : candidates) {
if (candidate != null) {
result.add(candidate);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace(\"Filtered \" + numberFiltered + \" auto configuration class in \"
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + \" ms\");
}
return result;
}
}

过滤完成后执行fireAutoConfigurationImportEvents(configurations, exclusions); 这部分不重要 ,可以看成就是记录一个日志,哪些成功的哪些被排除的。
最后执行return new AutoConfigurationEntry(configurations, exclusions); 这部分代码把 可以加载的自动配置类 放入到一个集合,把排除的放入到另一个集合
AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {
this.configurations = new ArrayList<>(configurations);
this.exclusions = new HashSet<>(exclusions);
}
public List<String> getConfigurations() {
return this.configurations;
}
public Set<String> getExclusions() {
return this.exclusions;
}

到此所有需要加载的自动配置类都找到了。然后再回到一开始的selectImports方法这个方法最后返回StringUtils.toStringArray(autoConfigurationEntry.getConfigurations())。返回所有符合自动配置类的全类名。根据@Import功能会继续将selectImports返回的类名,当成配置类去加载。那么每个自动配置类就会加载到springboot当中。
到此springboot自动配置功能就结束了。至于加载自动配置类加载过程中,根据条件注解去匹配是否能够加载,下一篇在分析。

总结

springboot启动类中存在@SpringBootApplication,而@SpringBootApplication中包含@EnableAutoConfiguration。@EnableAutoConfiguration中通过@Import引入AutoConfigurationImportSelector。
spring启动的时候调用AutoConfigurationImportSelector的selectImports。该方法获取到所有可以加载的自动配置类(此时还未加载)
获取过程如下:

  1. 获取@EnableAutoConfiguration的属性的值封装成AnnotationAttributes
  2. 获取spring.factories中key为EnableAutoConfiguration的值作为自动配置类的名称
  3. 将获取到的所有的自动配置类的名称进行去重
  4. 获取程序员配置的需要排除的自动配置类,从上一步找到的所有自动配置类中排除掉
  5. 获取spring.factories中key为AutoConfigurationImportFilter的值作为过滤器封装成ConfigurationClassFilter
  6. 通过ConfigurationClassFilter初次过滤不满足条件的自动配置类
  7. 把排除的自动配置类和最终可加载的自动配置类进行日志记录
  8. 把排除的自动配置类和最终可加载的自动配置类分别放入到集合当中,封装成AutoConfigurationEntry返回

最后selectImports从AutoConfigurationEntry拿出可加载的自动配置类的名称返回。这样springboot就会去加载那些配置类

资源下载此资源下载价格为1小猪币,终身VIP免费,请先
由于本站资源来源于互联网,以研究交流为目的,所有仅供大家参考、学习,不存在任何商业目的与商业用途,如资源存在BUG以及其他任何问题,请自行解决,本站不提供技术服务! 由于资源为虚拟可复制性,下载后不予退积分和退款,谢谢您的支持!如遇到失效或错误的下载链接请联系客服QQ:442469558

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 PHP教程 SpringBoot自动配置源码深入刨析讲解 http://www.20zxx.cn/585820/xuexijiaocheng/qes.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务