在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

点击查看美码师的 SpringBoot 补习系列

Y服务-你真的懂 Yaml 吗的更多相关文章

  1. #华为云·寻找黑马程序员#微服务-你真的懂 Yaml 吗?

    在Java 的世界里,配置的事情都交给了 Properties,要追溯起来这个模块还是从古老的JDK1.0 就开始了的. "天哪,这可是20年前的东西了,我居然还在用 Properties. ...

  2. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  3. “三次握手,四次挥手”你真的懂吗?TCP

    “三次握手,四次挥手”你真的懂吗?  mp.weixin.qq.com 来源:码农桃花源 解读:“拼多多”被薅的问题出在哪儿?损失将如何买单? 之前有推过一篇不错的干货<TCP之三次握手四次挥手 ...

  4. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  5. C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

  6. 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??

    原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...

  7. javascript的语法作用域你真的懂了吗

    原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...

  8. 你真的懂ajax吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

  9. 你真的懂 ajax 吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

随机推荐

  1. Maven 安装和使用

    Maven 安装和使用 1.下载 http://maven.apache.org/download.cgi 2.tar -bin.tar.gz 3.环境变量 /etc/profile export M ...

  2. 一份React-Native学习指南

    直击现场 学习React-Native过程中整理的一份学习指南,包含 教程.开源app和资源网站等,还在不断更新中.欢迎pull requests! React-Native学习指南 本指南汇集Rea ...

  3. C# 对字段忽略模型校验

    1.在if (!ModelState.IsValid)之前给字段赋值,然后TryUpdateModel()2.使用如下方法 public ActionResult Create([Bind(Exclu ...

  4. jQuery中的Ajax应用<思维导图>

    传统的WEB应用程序模型是这样工作的:当用户的界面操作触发HTTP请求,服务器在接到请求后进行一些业务逻辑处理,如保存数据等,然后向客户端返回一个html页面.但这种方式并没有给予用户很好的应用体验, ...

  5. PHP实现图片(文件)上传

    这几天整理做过的php项目,感觉这个经常会用到,传上来共享一下咯 首先,前端界面 1.表单的首行需要加上enctype="multipart/form-data",需要上传的图片必 ...

  6. 玩转Java多线程(乒乓球比赛)

    转载请标明博客的地址 本人博客和github账号,如果对你有帮助请在本人github项目AioSocket上点个star,激励作者对社区贡献 个人博客:https://www.cnblogs.com/ ...

  7. Tido c++线段树知识讲解(转载)

    线段树知识讲解 定义.建树.单点修改.区间查询         特别声明:如上的讲解说的是区间最大值 如果想要查询区间和 只需要改变一下建树和查询的代码就行了,如下 其他根据自己的需要进行修改即可

  8. Linux基础及系统优化

    1 如何实现自动挂载操作(光驱自动挂载--fstab) 1.1 方法 第一种方法:编辑fstab文件 vi /etc/fstab /dev/cdrom /mnt iso9660 default 0 0 ...

  9. Liunx 安装 Nessus

    Liunx 安装 Nessus   啥子是Nessus 它是一款系统漏洞扫描与分析软件,可以扫描服务器存在哪些漏洞,页面简介美观,非常Nice. 获取激活码 首先访问如下网站 https://www. ...

  10. 长春理工大学第十四届程序设计竞赛(重现赛)F

    F. Successione di Fixoracci 题目链接:https://ac.nowcoder.com/acm/contest/912/F 题目: 动态规划(Dynamic programm ...