Y服务-你真的懂 Yaml 吗
在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:14: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
Y服务-你真的懂 Yaml 吗的更多相关文章
- #华为云·寻找黑马程序员#微服务-你真的懂 Yaml 吗?
在Java 的世界里,配置的事情都交给了 Properties,要追溯起来这个模块还是从古老的JDK1.0 就开始了的. "天哪,这可是20年前的东西了,我居然还在用 Properties. ...
- [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?
你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...
- “三次握手,四次挥手”你真的懂吗?TCP
“三次握手,四次挥手”你真的懂吗? mp.weixin.qq.com 来源:码农桃花源 解读:“拼多多”被薅的问题出在哪儿?损失将如何买单? 之前有推过一篇不错的干货<TCP之三次握手四次挥手 ...
- 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截
程序猿修仙之路--数据结构之你是否真的懂数组? 数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构 .要想在之后的江湖历练中通关,数据结构必不可少. ...
- C# 知识回顾 - 你真的懂异常(Exception)吗?
你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...
- 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??
原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...
- javascript的语法作用域你真的懂了吗
原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...
- 你真的懂ajax吗?
前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...
- 你真的懂 ajax 吗?
前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...
随机推荐
- TCanvas 类属性及方法
delphi TCanvas类 类关系 TObject-> TPersistent 对那些作图对象,可使用TCanvas对象作为画布.标准的window控件,例如编辑控件和列表框控件,当 ...
- elasticsearch.yml 常用参数说明
cluster.name: 指定node所属的cluster. node.name: 本机的hostname. node.master: 是否可以被选举为master节点.(true or false ...
- 发现 TSplitter 在嵌套时不好用, 索性写了个替代品(处理MouseDown,MouseMove,MouseUp,然后设定控件的Left值就可以了)
代替 TSplitter 的 TDirPanel 类: unit DirPanel; interface uses Classes, Controls, Forms, ExtCtrls; type ...
- Vbox中Linux虚拟机网络配置(比较实用)
好久没写过东西了,主要大部分都是来自对生活的感悟,很少有实实在在的关于学得有成就感的技术可以“炫耀”,所以也就懒得在这个上面登了. 实验室很早就有位师兄曾在吃饭的路上问过我们这群小弟,你们知道Vbox ...
- HTML连载16-颜色控制属性2&标签选择器
一.颜色控制属性(上接连载15) (4)十六进制 在前端开发中通过十六进制来表示颜色,其实本质就是RGB,十六进制中是通过每两位表示一个颜色. 例如:#FFEE00,其中FF代表的是R,EE代表的G, ...
- Dubbo详解-说明(一)
Dubbo 是什么? Dubble是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理的方案. Dubbo 有啥特点? 远程通讯:提供透明化的远程方法的调用,提供 ...
- 电商、P2P等大型互联网系统包含哪些业务模块?
01 前言 在互联网飞速发展的时代,各大互联网公司正在进行激烈的竞争,业务模式也在不断的扩张,这种现状使得目前各大公司的架构系统面临着极大的挑战,而对于我们普通的软件开发者而言,如果你仅仅了解过一些关 ...
- phpstorm+xdebug手机app调试
1.安装过程网上搜一下全都是,这里省略. 2.由于debug调试需要去判断cookie中XDEBUG_SESSION,然后去调试.由于app接口请求没法去传,而且就算去传递也很麻烦,还要让app去改动 ...
- storm资源冲突
本方案出自<storm应用实践:实时事务处理之策略>,简略的写了一部分,详细的方法就看书吧 1)集群中工作进程冲突: 解决:通过查看stormUI cluster summary中的fre ...
- php使用webservice调用C#服务端/调用PHP服务端
由于公司业务需要,用自产平台对接某大厂MES系统,大厂提出使用webservice来互通,一脸懵逼啊,一直没有使用过php的webservice的我,瞬间打开手册开始阅读,最终爬过无数坑之后,总结出如 ...