当前位置: 首页 > news >正文

10、SpringBoot 源码分析 - 自动配置深度分析三

SpringBoot 源码分析 - 自动配置深度分析三

  • refresh和自动配置大致流程
  • AutoConfigurationImportSelector的getAutoConfigurationEntry获取自动配置实体(重点)
    • AutoConfigurationImportSelector的getCandidateConfigurations获取EnableAutoConfiguration类型的名字集合
    • AutoConfigurationImportSelector的removeDuplicates去重
    • AutoConfigurationImportSelector的getExclusions获取要排除的
    • AutoConfigurationImportSelector的checkExcludedClasses检查要排除的
    • AutoConfigurationImportSelector的filter过滤

refresh和自动配置大致流程

在这里插入图片描述

AutoConfigurationImportSelector的getAutoConfigurationEntry获取自动配置实体(重点)

前面讲了那么多,都是为了这里啊,不然直接上来都不知道是怎么来的,我们来看看这个干了什么,别看就那么点,其实里面很复杂,简单的说就是从我们初始化加载的所有的jar包下的META-INF/spring.factories属性中找到org.springframework.boot.autoconfigure.EnableAutoConfiguration属性,其实这个时候以及有缓存啦,前面初始化的时候已经全加载过了。然后进行去重,再获取要排除的名字,检查排除的类的合理性,然后排除,再进行条件类过滤,因为可能有些配置类缺少某些类就不能用了,触发自动装配导入事件,最后封装成AutoConfigurationEntry返回。

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//获取自动装配类configurations = removeDuplicates(configurations);//去重Set<String> exclusions = getExclusions(annotationMetadata, attributes);//获取要排除的checkExcludedClasses(configurations, exclusions);//检查要排除的configurations.removeAll(exclusions);//排除configurations = filter(configurations, autoConfigurationMetadata);//过滤fireAutoConfigurationImportEvents(configurations, exclusions);//触发导入事件return new AutoConfigurationEntry(configurations, exclusions);}

主要自动配置类都在这里,当然我们可以自定义,后面我们会自定义一个:
在这里插入图片描述

AutoConfigurationImportSelector的getCandidateConfigurations获取EnableAutoConfiguration类型的名字集合

这个代码我们前面很熟悉啊,就不多说了,从缓存中加载对应EnableAutoConfiguration类型的类名字,最终加载了124个,好多啊,没关系,后面过滤就没那么多了。

在这里插入图片描述

AutoConfigurationImportSelector的removeDuplicates去重

这个很巧妙,放进Set里又拿出来放进List里:

	protected final <T> List<T> removeDuplicates(List<T> list) {return new ArrayList<>(new LinkedHashSet<>(list));}

AutoConfigurationImportSelector的getExclusions获取要排除的

其实就是从注解属性的excludeexcludeName获取,当然还有个环境配置属性spring.autoconfigure.exclude也可以,就是说可以在yml或者propertise里配啦,其他就不多说了。
在这里插入图片描述
在这里插入图片描述

AutoConfigurationImportSelector的checkExcludedClasses检查要排除的

其实就是看下要排除的在不在自动配置集合里,有不在的就报异常,可能要排除的并不是自动配置的类,表示无效排除:

	private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {List<String> invalidExcludes = new ArrayList<>(exclusions.size());for (String exclusion : exclusions) {if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {invalidExcludes.add(exclusion);//不在自动配置类里,还要排除的,属于无效排除,要抛异常}}if (!invalidExcludes.isEmpty()) {handleInvalidExcludes(invalidExcludes);}}protected void handleInvalidExcludes(List<String> invalidExcludes) {StringBuilder message = new StringBuilder();for (String exclude : invalidExcludes) {message.append("\t- ").append(exclude).append(String.format("%n"));}throw new IllegalStateException(String.format("The following classes could not be excluded because they are not auto-configuration classes:%n%s",message));}

AutoConfigurationImportSelector的filter过滤

这里会获取过滤器,其实就是OnClassConditionOnWebApplicationConditionOnBeanCondition这几个条件,他会去配置类的注解上查找相应的条件类是否存在,不存在就会被过滤掉,过滤的时候可能会开启线程,帮助一起处理,因为配置类数量多。如果多核的话,会用启动一个线程去分担一半数量的检查,会判断条件类是否能加载到,不能就被过滤掉了,如果用多个线程可能效果不太好,spring团队应该做过实验,2个最好。

private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {long startTime = System.nanoTime();// 转换自动配置类的List集合为String数组String[] candidates = StringUtils.toStringArray(configurations);// 存储最终的匹配结果,和candidates数组索引位置一一对应,true代表最终需要// 自动引入,false代表不需要自动引入boolean[] skip = new boolean[candidates.length];boolean skipped = false;// <AutoConfigurationImportSelector#filter_1>见详细讲解for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {// <AutoConfigurationImportSelector#filter_2>见详细讲解invokeAwareMethods(filter);// <AutoConfigurationImportSelector#filter_3>见详细讲解boolean[] match = filter.match(candidates, autoConfigurationMetadata);// 循环当前的自动引入过滤器过滤结果,并记录过滤结果,用于后续逻辑过滤使用for (int i = 0; i < match.length; i++) {if (!match[i]) {skip[i] = true;candidates[i] = null;skipped = true;}}}// 当没有需要过滤的自动配置类时,会进if直接返回,否则执行后续逻辑,通过布尔数组进行过滤if (!skipped) {return configurations;}// 存储过滤后需要自动配置的类List<String> result = new ArrayList<>(candidates.length);for (int i = 0; i < candidates.length; i++) {// 如果当前位置为fasle则说明不需要跳过,则添加到最终结果中if (!skip[i]) {result.add(candidates[i]);}}// <AutoConfigurationImportSelector#filter_4>见详细讲解if (logger.isTraceEnabled()) {int numberFiltered = configurations.size() - result.size();logger.trace("Filtered " + numberFiltered + " auto configuration class in "+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");}// 返回结果,不知道为什么要再重新new一个return new ArrayList<>(result);
}

相关文章:

  • Git系列:git init 深入理解及其使用技巧
  • vmware 安装系统提示无法启用3D加速的解决
  • Linux基础 -- perf工具使用及加载符号表
  • c语言:利用随机函数产生20个[120, 834] 之间互不相等的随机数, 并利用选择排序法将其从小到大排序后输出(每行输出5个)
  • 基于双向长短期记忆 Bi-LSTM 对消费者投诉进行多类分类
  • RS8751XF功能和参数介绍及PDF资料
  • springboot webservice接口一个配置文件配置两个接口路径
  • GBase 8s 检查是否是IP且转数值函数
  • 秀某动预约抢票脚本
  • 几个速度比较快的 Linux 开源镜像站
  • kubectl详解
  • Python TCP编程简单实例
  • c语言,java语言,python语言之间有什么区别
  • 解决updateByExample时属性值异常的问题(部分属性值没有使用占位符?进行占位,而是变成了属性的名称)
  • MyBatis入门——MyBatis XML配置文件(3)
  • 2017-09-12 前端日报
  • 5、React组件事件详解
  • FineReport中如何实现自动滚屏效果
  • iOS | NSProxy
  • Java程序员幽默爆笑锦集
  • LeetCode18.四数之和 JavaScript
  • MobX
  • windows下如何用phpstorm同步测试服务器
  • 高性能JavaScript阅读简记(三)
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 使用putty远程连接linux
  • 小试R空间处理新库sf
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (Java数据结构)ArrayList
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (黑马C++)L06 重载与继承
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .net打印*三角形
  • .NET企业级应用架构设计系列之开场白
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • /etc/fstab 只读无法修改的解决办法
  • /proc/vmstat 详解
  • @Transaction注解失效的几种场景(附有示例代码)
  • [ HTML + CSS + Javascript ] 复盘尝试制作 2048 小游戏时遇到的问题
  • [ajaxupload] - 上传文件同时附件参数值
  • [C++]unordered系列关联式容器
  • [CCF-CSP] 202303-4 星际网络II
  • [Effective C++读书笔记]0012_复制对象时勿忘其每一部分
  • [jQuery]使用jQuery.Validate进行客户端验证(中级篇-上)——不使用微软验证控件的理由...
  • [lesson17]对象的构造(上)
  • [Linux]如何理解kernel、shell、bash
  • [Linux]----文件操作(复习C语言+文件描述符)
  • [MT8766][Android12] 增加应用安装白名单或者黑名单
  • [nlp] grad norm先降后升再降