在Java 的世界里,配置的事情都交给了 Properties,要追溯起来这个模块还是从古老的JDK1.0 就开始了的。

"天哪,这可是20年前的东西了,我居然还在用 Properties.."

然而,本文的主角并不是Properties,而是Yaml。这是新时代里微服务架构上的宠儿,和 Properties 相比起来,Yaml 显得有些弄潮儿。

以往的大多数项目里,我们都可以发现 Properties配置文件的踪迹,这包括用于业务属性配置的、机机接口的、国际化的等等用途。

而少量的一些情况下,也存在一些"混合式"的做法,比如:

  • 使用 Xml 来表示一些模板

  • 使用一个 Json 格式化的字符串

  • 裸奔的文本格式,应用自解析

    ...

混杂的配置方式往往出现在一些充满"坏味道"的项目里头,因为代码陈旧、斯人已矣 等原因,很难形成统一的方式。

然而,除开 Properties 属性文件这种简单的配置方式之外,采用其他的方法不外乎都是为了适应配置复杂、多元化的诉求。

那么,Yaml 就是应对这种场景而产生的,在 SpringBoot 的官方文档中,有不少篇幅是 使用了 Yaml 语法的配置格式。

下面介绍一下 Yaml 以及它是如何使用的。

一、什么是 Yaml

来自百科的定义:

"Yaml 是一个可读性高,易用的数据序列化格式,由 Clark Evans 在2001年首次发表。"

可见 Yaml 并不是一个很新的东西,只是在以前接触的人不多罢了。此外,Yaml也被各种编程语言及框架所支持, 通用性很高。

在Java体系中,一般的微服务框架都支持甚至优先推荐使用 Yaml 作为首选的配置语言。

而 Yaml 本身具有什么特点? 看看下面的一个实例:

environments:
dev:
url: https://dev.example.com
name: Developer Setup
prod:
url: https://another.example.com
name: My Cool App

这段语法等价的 Properties 为:

environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App

可见, yaml 相对来说更加的结构化,更适合用来表达一个对象。

它在语法上有这样的特点:

  • 大小写敏感

  • 使用空格缩进表示层级关系,摒弃使用Tab键,这主要是考虑到不同平台上文本展现时需要对齐

  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

  • 使用 # 开头作为注释行

  • 使用 连接符(-)开头来描述数组元素

对比 Properties 

Properties 可以很好的实现 Key-Value 的配置,包括作为一些国际化内容的配置方式。

但 Properties 很难表现多层级的嵌套关系,此时如果用 Yaml 可以较好的弥补该短板。

对比 Json

Yaml 与 Json本身没有太多的优劣之分,两者都是结构化的表达式语言,但是Json的设计重点在于简单易用、方便传输的特性;

而 Yaml 则侧重于可读性(更加在乎外观),几乎可以把 Yaml 看做是 Json 的一个"超集",即可读性更高(更漂亮) 的结构化格式。

此外,Json更加便于生成和解析,适合在各种跨语言、分布式的环境中传输和交互;与此同时, Yaml 则一般只是用作的配置较多。

关于 Yaml 的定义可以访问下面的地址:
http://www.yaml.org/spec/1.2/spec.html

二、Yaml 的语法

Yaml 是非常简单的, 它所定义的元素只有三个:

  • 对象:就是键值对的集合,对应于Java 中的 HashMap

  • 数组:指一组按序排列的值,对应于Java 中的 List

  • 单值:单个的、不可再分的值,比如 3,"Jackson"

对象如何表示

一个对象的属性、嵌套关系通过空格缩进对齐来表示,如下:

article:
title: 一个人的自白书
author:
name: 陈玲
gender: female

数组如何表示

数组的元素通过连接符(-)来表示,如下:

article:
title: 一个人的自白书
tags:
- 传记
- 社会
- 人物

构成对象、数组内容的基本单元是单值,Yaml支持的单个值的类型有七种,如下:

类型 范例
字符串 Bob
布尔值 true
整数 199
浮点数 19.91
Null ~
时间 2001-12-14T22.09.10+08:00
日期 2019-01-09

其中,日期、时间使用的是 ISO 8601 国际标准格式,关于它的定义可以参考:
https://www.w3.org/TR/NOTE-datetime

一般情况下单个值会在一行内结束。但如果遇到多行的字符串,可以使用一些特殊字符表示,

比如:

text: |
Hello
World

对应的结果为:

{ text: 'Hello\nWorld\n' }

可以用+表示保留字符串末尾的换行,-表示删除字符串末尾的换行:

text1: |+
Hello text2: |-
Hello

对应的结果为:

{ text1: 'Hello\n\n\n', text2: 'Hello' }

除此之外,Yaml 还可以支持引用、函数、正则表达式等高级用法,但项目上一般很少用到。

三、操作 Yaml

目前用来操作 Yaml 的常用组件是 Snake Yaml,这个库支持标准的 Yaml 1.1 版本。

SpringBoot 官方文档也介绍了整合该框架的方式,参考下面的地址:
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-loading-yaml

下面提供 将SnakeYaml 整合到项目的样例。

A. 引入框架

在Maven的pom.xml文件中添加:

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.21</version>
</dependency>

B. 代码片段

实现加载配置文件

如下面的代码,实现了从类路径config.yml文件中加载 yaml 配置内容:

InputStream inputStream = YamlUtil.class.getClassLoader()
.getResourceAsStream("config.yml"); Yaml yaml = new Yaml();
Map<String, Object> objectMap = yaml.load(inputStream);
System.out.println(objectMap.get("path"));

实现对象转换

定义如下的Pojo 对象:

public static class A{
private String name = "hello";
private List<B> bs = new ArrayList<B>(); public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public List<B> getBs() {
return bs;
} public void setBs(List<B> bs) {
this.bs = bs;
}
} public static class B{
private String id = UUID.randomUUID().toString(); public String getId() {
return id;
} public void setId(String id) {
this.id = id;
}
}

通过 SnakeYaml 将对象输出为 Yaml 格式的代码:

A a = new A();
a.getBs().add(new B());
a.getBs().add(new B()); Yaml yaml = new Yaml();
String aString = yaml.dumpAsMap(a);
System.out.println(aString);

输出结果如下:

bs:
- id: b3688f05-ea7e-436b-bc9a-9c5df555c7fd
- id: 7906224d-8ecc-43b8-bc3b-07985bc18ebd
name: hello

此时如果希望将Yaml 文本反过来转换为 A 对象,可以执行下面的代码:

A a1 = new Yaml().parseToObject(aString, A.class);
...

C. 完整案例

最终,我们可以将 Yaml 文档的操作封装为一个工具类,方便在业务代码中集成。

YamlUtil.java

public class YamlUtil {

    /**
* 从资源文件加载内容,并解析为Map对象
*
* @param path
* @return
*/
public static Map<String, Object> loadToMap(String path) {
if (StringUtils.isEmpty(path)) {
return Collections.emptyMap();
} InputStream inputStream = YamlUtil.class.getClassLoader()
.getResourceAsStream(path); Yaml yaml = new Yaml();
Map<String, Object> objectMap = yaml.load(inputStream);
return objectMap;
} /**
* 将字符串解析为Map对象
*
* @param content
* @return
*/
public static Map<String, Object> parseToMap(String content) {
if (StringUtils.isEmpty(content)) {
return Collections.emptyMap();
} Yaml yaml = new Yaml();
Map<String, Object> objectMap = yaml.load(content);
return objectMap;
} /**
* 将字符串解析为类对象
*
* @param content
* @param clazz
* @param <T>
* @return
*/
public static <T> T parseToObject(String content, Class<T> clazz) {
if (StringUtils.isEmpty(content) || clazz == null) {
return null;
} Yaml yaml = new Yaml(new Constructor(clazz));
T object = yaml.load(content);
return object;
} /**
* 格式化对象
*
* @param object
* @return
*/
public static String format(Object object) {
Yaml yaml = new Yaml();
return yaml.dumpAsMap(object);
} }

至此,我们已经完成了 Yaml 的读写。当然,除了上述的Snake Yaml 之外,还可以使用 流行的 Jackson 组件了进行解析,这里不再过多赘述,有兴趣的朋友可以自行尝试。

参考文档

阮一峰-YAML语言教程:
http://www.ruanyifeng.com/blog/2016/07/yaml.html

SnakeYaml 官方文档:
https://bitbucket.org/asomov/snakeyaml/wiki/Documentation

Yaml 1.2 规范:
http://www.yaml.org/spec/1.2/spec.html

SpringBoot-LoadingYaml
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-loading-yaml

来源:华为云征文  作者:zale

#华为云·寻找黑马程序员#微服务-你真的懂 Yaml 吗?的更多相关文章

  1. python让你再也不为文章配图与素材发愁,让高清图片占满你的硬盘! #华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  2. 使用jieba分析小说太古神王中,男主更爱谁?去文章中找答案吧!#华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  3. 大型情感剧集Selenium:6_selenium中的免密登陆与cookie操作 #华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  4. Flask开发VIP版HttpServer #华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  5. 将Android手机打造成你的Python开发者桌面#华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

  6. #华为云·寻找黑马程序员#【代码重构之路】如何“消除”if/else

    1. 背景 if/else是高级编程语言中最基础的功能,虽然 if/else 是必须的,但滥用 if/else,特别是各种大量的if/else嵌套,会对代码的可读性.可维护性造成很大伤害,对于阅读代码 ...

  7. 大型情感剧集Selenium:1_介绍 #华为云·寻找黑马程序员#

    学习selenium能做什么? 很多书籍.文章中是这么定义selenium的: Selenium 是开源的自动化测试工具,它主要是用于Web 应用程序的自动化测试,不只局限于此,同时支持所有基于web ...

  8. #华为云·寻找黑马程序员# 如何实现一个优雅的Python的Json序列化库

    在Python的世界里,将一个对象以json格式进行序列化或反序列化一直是一个问题.Python标准库里面提供了json序列化的工具,我们可以简单的用json.dumps来将一个对象序列化.但是这种序 ...

  9. 使用Python开发小说下载器,不再为下载小说而发愁 #华为云·寻找黑马程序员#

    需求分析 免费的小说网比较多,我看的比较多的是笔趣阁.这个网站基本收费的章节刚更新,它就能同步更新,简直不要太叼.既然要批量下载小说,肯定要分析这个网站了- 在搜索栏输入地址后,发送post请求获取数 ...

随机推荐

  1. nginx篇最初级用法之地址重写

    nginx服务器的地址重写,主要用到的配置参数是rewrite rewrite regex replacement flag rewrite 旧地址 新地址 [选项] 支持的选项有: last 不再读 ...

  2. AndroidOS体系结构

    首先上图一张 对照着图,我们再来看Android 系统的体系结构就爽多了.我们从底层向上进行分析. 一.Linux 内核层 Linux Kernel 基于linux2.6.其核心系统服务如安全性.内存 ...

  3. vue引入百度地图 --BMap is not defined ,eslint BMap报错

    在mounted初始化地图的时候,因为异步问题会导致BMap is not defined,也就是百度的api还没完全引入或者加载完成,就已经进行地图初始化了 解决方法: 1.创建一个map.js e ...

  4. Tomcat+nginx+Keepalived部署实现集群

    Tomcat+nginx+Keepalived部署实现集群 环境说明: 系统:Centos-7 主机:Centos-7 x3 IP地址: 服务器1(192.168.10.102/24) 服务器2(19 ...

  5. linux破解密码

    1.关机2.按e进入grub 3.在linux16行末尾输入 rd.break console=tty1   4.按ctrl+“X”执行.  5.输入 mount -o remount,rw /sys ...

  6. Groovy单元测试框架spock基础功能Demo

    spock是一款全能型的单元测试框架. 最近在做单元测试框架的调研和尝试,目前确定的方案框架包括是:spock,Junit,Mockito以及powermock.由于本身使用Groovy的原因,比较钟 ...

  7. (二十六)golang--切片

    基本介绍: 切片是数组的引用: 切片的使用和数组类似: 切片的长度是可以变化的: 切片的定义 var a []int,注意和数组定义的区别: 切片不仅可以使用len函数,还有cap函数来计算切片的容量 ...

  8. hdu 1878 欧拉回路(联通<并查集> + 偶数点)

    欧拉回路Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  9. nyoj 204-Coin Test (python count)

    204-Coin Test 内存限制:64MB 时间限制:3000ms 特判: No 通过数:2 提交数:2 难度:1 题目描述: As is known to all,if you throw a ...

  10. 记录工作遇到的死锁问题(Lock wait timeout exceeded; try restarting transaction)

    1.问题背景 刚来新公司不久,对业务还不太熟悉,所以领导先安排我维护原有系统.大概介绍下项目背景,项目分为核心业务部分在项目A中,与第三方交互的业务在项目B中,前端发起请求调用A项目接口,并在A项目中 ...