在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. Jquery+CSS在不使用Checked的情况下实现当前选中行样式变化

    之前在做一个当前选中行样式变化时发现网上很多方法都是利用在行内添加checked,然后通过checked是否选中来判断当前选中行的位置,今天就整理了一个不需要在行内添加其他按钮直接通过变化当前选中行的 ...

  2. LeetCode刷题总结-数组篇(番外)

    本期共7道题,三道简单题,四道中等题. 此部分题目是作者认为有价值去做的一些题,但是其考察的知识点不在前三篇总结系列里面. 例1解法:采用数组索引位置排序的思想. 例2解法:考察了组合数学的组合公式应 ...

  3. 关于发送邮件,错误“命令顺序不正确。 服务器响应为:Error: need EHLO and AUTH first !”问题

    最近做了一个小程序,通过QQ邮箱服务器发送邮件, 代码写完后,运行调试,出现“命令顺序不正确. 服务器响应为:Error: need EHLO and AUTH first !”的问题, 上网查询发现 ...

  4. abp(net core)+easyui+efcore实现仓储管理系统——EasyUI之货物管理八(二十六)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  5. 【洛谷】P2371 [国家集训队]墨墨的等式(屠版题)

    先讲讲曲折的思路吧...... 首先,应该是CRT之类的东西,乱搞 不行......打了打草稿,发现有解的情况是gcd(a1,a2.....an)|B,于是可以求gcd然后O(n)查询?但是B的范围直 ...

  6. [转载]【转】教你如何实现linux和Windows之间的文件共享,samba的安

    原文地址:[转]教你如何实现linux和Windows之间的文件共享,samba的安装与配置作者:铅笔小蜡 本人在虚拟机下装fedora13,已经实现.1. 首先检查os是否安装好了samba. [r ...

  7. php 环境require(): open_basedir restriction in effect 错误

    php 环境require(): open_basedir restriction in effect 错误 错误日志显示,访问脚本不在 open_basedir的限定目录里面 解决方法打开fastc ...

  8. maven打包记录1

    在需要打包的项目目录下找到pom.xml文件 (过程中可能遇到 :-Dmaven.multiModuleProjectDirectory system property is not set. Che ...

  9. Laravel 5 - 文件上传

    一.简介 Laravel 有很棒的文件系统抽象层,是基于 Frank de Jonge 的 Flysystem 扩展包. Laravel 集成的 Flysystem 提供了简单的接口,可以操作本地端空 ...

  10. Hadoop压缩的图文教程

    近期由于Hadoop集群机器硬盘资源紧张,有需求让把 Hadoop 集群上的历史数据进行下压缩,开始从网上查找的都是关于各种压缩机制的对比,很少有关于怎么压缩的教程(我没找到..),再此特记录下本次压 ...