18张图带你看懂SpringBoot解析yml全流程

【SpringBoot】18张图,详解SpringBoot解析yml全流程_springboot解析注册yml文件源码 好了,让我们再回到上面的那张方法调用流程图,它是根据文章开头的yml文件中实际内容内容绘制的,如果内容不同调用流程会发生改变,大家只需要明白这个原理,下面我们具体分析。方法中,会通过嵌套循环方式遍历默认配置文件存放路径,再加上默认的配置文件名称、以及不同配置文件加载器对应解析的后缀名,最终找到我们的yml配置文件。但是当代码实际跑起来,有意思的地方来了,我们发现判断中的代码一直不会被执行,直到debug一下,才发现这里的取到的值居然不是。程序中的代码也很简单,大致的逻辑就是下面这样,如果取到的开关字段是。 阅读详情

 前几天的时候,项目里有一个需求,需要一个开关控制代码中是否执行一段逻辑,于是理所当然的在 yml 文件中配置了一个属性作为开关,再配合 nacos 就可以随时改变这个值达到我们的目的,yml文件中是这样写的:

switch:
  turnOn: on

程序中的代码也很简单,大致的逻辑就是下面这样,如果取到的开关字段是 on 的话,那么就执行 if 判断中的代码,否则就不执行:

@Value("${switch.turnOn}")
private String on;

@GetMapping("testn")
public void test(){
    if ("on".equals(on)){
        //TODO
    }
}

但是当代码实际跑起来,有意思的地方来了,我们发现判断中的代码一直不会被执行,直到debug一下,才发现这里的取到的值居然不是 on 而是 true 。

看到这,是不是感觉有点意思,首先盲猜是在解析yml的过程中把 on 作为一个特殊的值进行了处理,于是我干脆再多测试了几个例子,把yml中的属性扩展到下面这些:

switch:
  turnOn: on
  turnOff: off
  turnOn2: 'on'
  turnOff2: 'off'

再执行一下代码,看一下映射后的值:

可以看到,yml中没有带引号的 on 和 off 被转换成了 true 和 false ,带引号的则保持了原来的值不发生改变。

到这里,让我忍不住有点好奇,为什么会发生这种现象呢?于是强忍着困意翻了翻源码,硬磕了一下SpringBoot加载yml配置文件的过程,终于让我看出了点门道,下面我们一点一点细说!

因为配置文件的加载会涉及到一些SpringBoot启动的相关知识,所以如果对SpringBoot启动不是很熟悉的同学,可以先提前先看一下Hydra在古早时期写过一篇 Spring Boot零配置启动原理 预热一下。下面的介绍中,只会摘出一些对加载和解析配置文件比较重要的步骤进行分析,对其他无关部分进行了省略。

加载监听器

当我们启动一个SpringBoot程序,在执行 SpringApplication.run() 的时候,首先在初始化 SpringApplication 的过程中,加载了11个实现了 ApplicationListener 接口的拦截器。

这11个自动加载的 ApplicationListener ,是在 spring.factories 中定义并通过 SPI 扩展被加载的:

这里列出的10个是在 spring-boot 中加载的,还有剩余的1个是在 spring-boot-autoconfigure 中加载的。其中最关键的就是 ConfigFileApplicationListener ,它和后面要讲到的配置文件的加载相关。

执行run方法

在实例化完成 SpringApplication 后,会接着往下执行它的 run 方法。

可以看到,这里通过 getRunListeners 方法获取的 SpringApplicationRunListeners 中, EventPublishingRunListener 绑定了我们前面加载的11个监听器。但是在执行 starting 方法时,根据类型进行了过滤,最终实际只执行了 4个 监听器的 onApplicationEvent 方法,并没有我们希望看到的 ConfigFileApplicationListener ,让我们接着往下看。

当 run 方法执行到 prepareEnvironment 时,会创建一个 ApplicationEnvironmentPreparedEvent 类型的事件,并广播出去。这时所有的监听器中,有7个会监听到这个事件,之后会分别调用它们的 onApplicationEvent 方法,其中就有了我们心心念念的 ConfigFileApplicationListener ,接下来让我们看看它的 onApplicationEvent 方法中做了什么。

在方法的调用过程中,会加载系统自己的4个后置处理器以及 ConfigFileApplicationListener 自身,一共5个后置处理器,并执行他们的 postProcessEnvironment 方法,其他4个对我们不重要可以略过,最终比较关键的步骤是创建 Loader 实例并调用它的 load 方法。

加载配置文件

这里的 Loader 是 ConfigFileApplicationListener 的一个内部类,看一下 Loader 对象实例化的过程:

在实例化 Loader 对象的过程中,再次通过SPI扩展的方式加载了两个属性文件加载器,其中的 YamlPropertySourceLoader 就和后面的yml文件的加载、解析密切关联,而另一个 PropertiesPropertySourceLoader 则负责 properties 文件的加载。创建完 Loader 实例后,接下来会调用它的 load 方法。

在 load 方法中,会通过嵌套循环方式遍历默认配置文件存放路径,再加上默认的配置文件名称、以及不同配置文件加载器对应解析的后缀名,最终找到我们的yml配置文件。接下来,开始执行 loadForFileExtension 方法。

在 loadForFileExtension 方法中,首先将 classpath:/application.yml 加载为 Resource 文件,接下来准备正式开始,调用了之前创建好的 YamlPropertySourceLoader 对象的 load 方法。

封装Node

在 load 方法中,开始准备进行配置文件的解析与数据封装:

load 方法中调用了 OriginTrackedYmlLoader 对象的 load 方法,从字面意思上我们也可以理解,它的用途是原始追踪yml的加载器。中间一连串的方法调用可以忽略,直接看最后也是最重要的是一步,调用 OriginTrackingConstructor 对象的 getData 接口,来解析yml并封装成对象。

在解析yml的过程中实际使用了 Composer 构建器来生成节点,在它的 getNode 方法中,通过解析器事件来创建节点。通常来说,它会将yml中的一组数据封装成一个 MappingNode 节点,它的内部实际上是一个 NodeTuple 组成的 List , NodeTuple 和 Map 的结构类似,由一对对应的 keyNode 和 valueNode 构成,结构如下:

好了,让我们再回到上面的那张方法调用流程图,它是根据文章开头的yml文件中实际内容内容绘制的,如果内容不同调用流程会发生改变,大家只需要明白这个原理,下面我们具体分析。

首先,创建一个 MappingNode 节点,并将 switch 封装成 keyNode ,然后再创建一个 MappingNode ,作为外层 MappingNode 的 valueNode ,同时存储它下面的4组属性,这也是为什么上面会出现4次循环的原因。如果有点困惑也没关系,看一下下面的这张图,就能一目了然了解它的结构。

在上图中,又引入了一种新的 ScalarNode 节点,它的用途也比较简单,简单String类型的字符串用它来封装成节点就可以了。到这里,yml中的数据被解析完成并完成了初步的封装,可能眼尖的小伙伴要问了,上面这张图中为什么在 ScalarNode 中,除了 value 还有一个 tag 属性,这个属性是干什么的呢?

在介绍它的作用前,先说一下它是怎么被确定的。这一块的逻辑比较复杂,大家可以翻一下 ScannerImpl 类 fetchMoreTokens 方法的源码,这个方法会根据yml中每一个 key 或 value 是以什么开头,来决定以什么方式进行解析,其中就包括了 { 、 [ 、 ' 、 % 、 ? 等特殊符号的情况。以解析不带任何特殊字符的字符串为例,简要的流程如下,省略了一些不重要部分:

在这张图的中间步骤中,创建了两个比较重要的对象 ScalarToken 和 ScalarEvent ,其中都有一个为 true 的 plain 属性,可以理解为这个属性是否需要 解释 ,是后面获取 Resolver 的关键属性之一。

上图中的 yamlImplicitResolvers 其实是一个提前缓存好的HashMap,已经提前存储好了一些 Char 类型字符与 ResolverTuple 的对应关系:

当解析到属性 on 时,取出首字母 o 对应的 ResolverTuple ,其中的 tag 就是 tag:yaml.org.2002:bool 。当然了,这里也不是简单的取出就完事了,后续还会对属性进行正则表达式的匹配,看与 regexp 中的值是否能对的上,检查无误时才会返回这个 tag 。

到这里,我们就解释清楚了 ScalarNode 中 tag 属性究竟是怎么获取到的了,之后方法调用层层返回,返回到 OriginTrackingConstructor 父类 BaseConstructor 的 getData 方法中。接下来,继续执行 constructDocument 方法,完成对yml文档的解析。

调用构造器

在 constructDocument 中,有两步比较重要,第一步是推断当前节点应该使用哪种类型的构造器,第二步是使用获得的构造器来重新对 Node 节点中的 value 进行赋值,简易流程如下,省去了循环遍历的部分:

推断构造器种类的过程也很简单,在父类 BaseConstructor 中,缓存了一个HashMap,存放了节点的 tag 类型到对应构造器的映射关系。在 getConstructor 方法中,就使用之前节点中存入的 tag 属性来获得具体要使用的构造器:

当 tag 为 bool 类型时,会找到 SafeConstruct 中的内部类 ConstructYamlBool 作为构造器,并调用它的 construct 方法实例化一个对象,来作为 ScalarNode 节点的 value 的值:

在 construct 方法中,取到的val就是之前的 on ,至于下面的这个 BOOL_VALUES ,也是提前初始化好的一个HashMap,里面提前存放了一些对应的映射关系,key是下面列出的这些关键字,value则是 Boolean 类型的 true 或 false :

到这里,yml中的属性解析流程就基本完成了,我们也明白了为什么yml中的 on 会被转化为 true 的原理了。至于最后, Boolean 类型的 true 或 false 是如何被转化为的字符串,就是 @Value 注解去实现的了。

思考

那么,下一个问题来了,既然yml文件解析中会做这样的特殊处理,那么如果换成 properties 配置文件怎么样呢?

sw.turnOn=on
sw.turnOff=off

执行一下程序,看一下结果:

可以看到,使用 properties 配置文件能够正常读取结果,看来是在解析的过程中没有做特殊处理,至于解析的过程,有兴趣的小伙伴可以自己去阅读一下源码。

原文链接:http://www.cnblogs.com/trunks2008/p/15801140.html

Springboot 的启动流程【超级详细 | 附带思维导图】 中,请求的处理是通过一系列的过滤器(Filter)来实现的。发布应用已启动事件(ApplicationStartedEvent)的主要作用是提供一个时机点,让我们能在应用完全启动后,但在开始接收请求之前执行一些初始化操作。这个事件的触发标志着应用已经完全启动,所有的核心组件都已经初始化完成,可以开始处理业务请求了。这个阶段完成后,所有的Bean都已经创建完成并完成了依赖注入,应用程序已经准备好处理请求了。这个阶段是应用启动的最后一步,适合执行一些初始化操作,但要注意不要影响应用的正常启动。 阅读详情

相关推荐

Spring Boot 概要(官网文档解读)

Spring Boot 是一个高效构建 Spring 生产级应用的脚手架工具,它简化了基于 Spring 框架的开发过程。该文章是小编对于Spring Boot基于官方文档学习的总结。感兴趣的小伙伴可以参考该文章进行学习。

wend的博客 3939

springboot框架图解

一图胜千言: springboot容器启动流程: 其中最重要的: 运行机制为: springboot事件驱动:详情见:springboot事件驱动与观察者模式(http://www.cnblogs.com/dennyzhangdd/p/8343229.html) springboot启动流程图: 分层图: ...

远行的博客 5万+

Springboot源码流程图

starter包含了搭建项目快速运行所需的依赖。它是一个依赖关系描述符的集合。当应用需要一种spring的其它服务时,不需要粘贴拷贝大量的依赖关系描述符。例如想在spring中使用redis,只需要在项目中包含 spring-boot-starter-redis 依赖就可以使用了,所有的starters遵循一个相似的命名模式:spring-boot-starter-,在这里是一种特殊类型的应用程序。该命名结构可以帮你找到需要的starter。很多IDEs集成的Maven允许你通过名称搜索依赖。 ———————————————— 版权声明:本文为优快云博主「weixin_43594111」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.youkuaiyun.com/weixin_43594111/article/details/105966928

springboot启动流程源码解析(带流程图)

springboot启动流程源码解析(带流程图)

zkr1234562的博客 5042

使用.NET 免费开源包ViewFaceCore做一个人脸识别并注册的功能,没有比我更全的

本文介绍了一个基于WinForm的免费人脸识别系统实现方案。系统使用AForge和ViewFaceCore库,支持从USB或电脑自带摄像头采集图像,具备人脸注册和快速识别功能。硬件方面仅需普通摄像头,软件依赖多个NuGet包(如AForge.Video、ViewFaceCore等)。界面包含视频显示、图像预览和功能按钮控件,后台采用SQLServer存储用户面部特征数据。核心代码展示了人脸检测、特征提取和多线程处理逻辑,通过ViewFaceCore实现高效识别。系统具有识别速度快、准确率高的特点,适合Win

一个靠“吃代码”长大的程序猿,专治各种“Bug 饥饿症”。 817

Web自动化神操作:如何用OpenCV 破解滑块验证码?

验证码作为一种安全机制,可以有效防止暴力破解密码、发帖、灌水、刷票等,大家在做 Web 自动化的时候应该有碰到验证码这个难题,一般我们可以和开发沟通请求他们的帮助:去掉验证码或者设置一个万能验证码,而如果开发不帮忙我们该如何去解决呢? 本篇文章以 Java 语言为例教你怎么破解验证码。 现在大多数网址会采用滑块验证码的方式,下面以腾讯的滑块验证码为例,先来看看破解的效果: 要破解滑块验证码,我们一般采取的思路如下: 获取滑块到背景缺口图的距离 通过 selenium 的 Actio

不喝枸杞的程序员 2035

【SpringBoot】18张图,详解SpringBoot解析yml全流程

前几天的时候,项目里有一个需求,需要一个开关控制代码中是否执行一段逻辑,于是理所当然的在 yml 文件中配置了一个属性作为开关,再配合 nacos 就可以随时改变这个值达到我们的目的,yml文件中是这样写的

阿Q的小窝 8590

`tokenizer.decode` 出现乱码或异常输出,怎么处理

摘要: 在使用Hugging Face Transformers库时,tokenizer.decode出现乱码或异常输出的解决方案包括:1)确保模型与分词器严格匹配,加载时使用trust_remote_code=True;2)谨慎处理特殊token,先保留所有token再针对性清理;3)校验模型输出token的维度和数值是否合法;4)通过convert_tokens_to_string替代解码;5)检查生成配置如max_new_tokens等参数。核心思路是确保模型与分词器逻辑对齐、输出token合法,必要

ZhangJiqun&191cm&85kg 583

18张图,详解SpringBoot解析yml全流程

原创:微信公众号 码农参上,欢迎分享,转载请保留出处。 前几天的时候,项目里有一个需求,需要一个开关控制代码中是否执行一段逻辑,于是理所当然的在yml文件中配置了一个属性作为开关,再配合nacos就可以随时改变这个值达到我们的目的,yml文件中是这样写的: switch: turnOn: on 程序中的代码也很简单,大致的逻辑就是下面这样,如果取到的开关字段是on的话,那么就执行if判断中的代码,否则就不执行: @Value("${switch.turnOn}") private String o.

1224

斗鱼直播间弹幕爬虫实战:WebSocket连接与实时数据采集

在数据驱动的时代,直播平台的弹幕数据蕴含着巨大的价值——用户行为分析、舆情监控、弹幕情感分析、直播热度评估等应用场景层出不穷。斗鱼作为国内领先的直播平台,其弹幕系统基于WebSocket协议实现实时双向通信。本文将带您从零开始,使用Python构建一个完整的斗鱼直播间弹幕爬虫系统。

2201_76125261的博客 133

大厂校招:星宸科技嵌入式面试及参考答案(5万字长文)

当一个新的硬件设备被插入系统时,内核会发送一个设备事件通知 udev,udev 会根据设备的属性和规则,为该设备创建一个合适的设备文件。通过去除不必要的驱动程序、禁用不需要的功能、选择合适的内核配置选项、优化内核编译选项和定制内核模块等方法,可以减小内核的大小和复杂性,提高系统的性能和稳定性。上半部通常是在中断关闭的情况下执行的,以确保中断处理的原子性。处理碎片化内存是内存管理中的一个重要问题,可以采用内存压缩、内存池管理、伙伴系统、首次适应算法和最佳适应算法等方法来减少内存碎片的产生,提高内存的利用率。

大模型大数据攻城狮的专栏 2924

【SpringBoot】18张图,详解SpringBoot解析yml全流程_springboot解析注册yml文件源码(1)

2020年在匆匆忙忙慌慌乱乱中就这么度过了,我们迎来了新一年,互联网的发展如此之快,技术日新月异,更新迭代成为了这个时代的代名词,坚持下来的技术体系会越来越健壮,JVM作为如今是跳槽大厂必备的技能,如果你还没掌握,更别提之后更新的新技术了。更多JVM面试整理:本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录需要这份系统化的资料的朋友,可以点击这里获取。

2401_84584740的博客 590

通过Simulink搭建一个智能微电网能量管理系统(Energy Management System, EMS)

通过上述代码实现,您可以逐步创建一个智能微电网能量管理系统。多源能量集成:整合光伏、风力发电、柴油发电机、电池储能等多种能源资源。负荷预测与调度:基于历史数据和天气预报,预测未来负荷和可再生能源输出,进行优化调度。储能系统优化:设计合理的充放电策略,确保储能系统的高效利用和寿命延长。经济性分析:评估不同运行模式下的经济性,考虑电价、维护成本等因素。环境影响评估:分析微电网对环境的影响,如减少碳排放、提高可再生能源利用率等。硬件在环仿真(HILS)

amy_mhd的博客 314

【热门文章解析】【SpringBoot】18张图,详解SpringBoot解析yml全流程

热门文章解析

A%B 137

【OpenCV-Python】——图像处理基础&读写及显示图像&读写及播放视频&灰度图/彩色图/图像通道操作、运算

在Python中,OpenCV使用NumPy数组存储图像,Numpy是使用Python进行数组计算的软件包,提供强大的N维数组对象,支持复杂的广播功能(数组运算),集成了C/C++和Fortran代码工具,支持线性代数、傅里叶变换和随机数等特性,还可作为通用数据的高效多维容器,如在OpenCV中显示图像。Numpy的知识点见数据处理专栏,主要包括数据类型、创建数组、数组形状、索引切片和迭代、数组运算等。作为初学者,里面可能有总结不全,后续深入学习后会改善文章!下次学习图形用户界面!

weixin_51658186的博客 2084

全志T527-TP9930-Camera

TP9930 驱动模块主要实现将 4 路的 AHD/TVI/CVBS Camera 的数据转换为 BT656/BT1120 数据,从而实现在 T527 端来对数据进行处理和送显。

Linux驱动开发工程师,熟悉Linux/Android底层驱动、TP、显示、IIC、网络等通用外设调试适配,Linux上层应用开发。常用平台瑞芯微、全志、恩智浦等。 3232

YML简介

在接触springboot的时候遇到了一种特殊的配置文件 .yml,本文对yml作简单介绍,快速入手yml。 一、YML是什么 YAML (YAML Aint Markup Language)是一种标记语言,通常以.yml或者.yaml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置...

ThinkWon的博客 4万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

YML的讲解-springboot

YML的定义 首先,我们看看YML的定义。YML(YAML):YAML Ain't Markup Language。它明确表明YML不是标记语言。它有很好的数据结构,方便程序员来阅读。 YML语法格式。占位符random的使用,占位符默认值的使用等 @Value与@ConfigurationProperties的用法

guocy_lm的专栏 1126

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

SpringBoot 项目中 YML 配置文件的使用

YML 是什么?YML (YAML Aint’t a Martup Language) YAML 不是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以与支持 YAML 库的编程语言所导入使用,一种专门用来写配置文件的语言。YAML 试图用一种比 XML 更敏捷的方式,来完成 XML 所完成的任务。

weixin_51262499的博客 5240

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

SpringBoot中.yml文件的使用

文章目录一、.yml 文件与其他配置文件的关系二、.yml 的创建三、.yml 文件书写规范示例四、.yml 文件的简单使用 一、.yml 文件与其他配置文件的关系 我们都在SpringBoot框架中见到过.yml 配置文件,我们通知把系统的很多配置信息放到这个配置文件中。但是除了.yml 文件,我们也见到过很多其他的配置文件,例如:.xml文件,.properties文件等,那他们之间有什么区别...

景月娇-Kathy 2580

springboot配置文件yml写法简介

springboot配置文件常用知识点 一、配置文件 SpringBoot使用一个全局的配置文件,配置文件名是固定的; application.properties application.yml 1、yml语法格式 ## 基本格式 server: port: 8080 ## 值的写法格式 user: name: zhangsan age: 20 ## 或者采...

狗狗大蛇 1282

【SpringBoot】三、yml配置文件

文章目录四、SpringBoot的配置文件4.1 SpringBoot配置文件类型4.2 配置文件与配置类的属性映射方式4.2.1 使用注解@Value映射4.2.2 使用注解@ConfigurationProperties映射 四、SpringBoot的配置文件 4.1 SpringBoot配置文件类型 SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置...

Java 316

SpringBoot项目解析yml文件

YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。

学习/总结 616
上一篇: 谈谈Java中让你眼花缭乱的18把锁
下一篇: 全网最新Java8特性大全
Java架构师小森
博客等级 码龄5年 23粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值