在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. VS2008 环境中完美搭建 Qt 4.7.4 静态编译的调试与发布(很不错,有六张插图说明,修改qmake.conf里的MD参数等)good

    为什么要在VS2008中使用QT静态编译呢?很简单,因为VS2008编译器编译出来的文件比mingw编译的要几乎小一半. 好了现在我们来做些准备工作,VS2008自然要安装的,然后打上SP1的补丁.然 ...

  2. python中的set集合和深浅拷贝

    一.基础数据类型的补充 1.str中的join算法,将列表转换成字符串,并用'_'(或其他) li=['李嘉诚','马化腾','刘嘉玲','黄海峰',] s='_'.join(li) print(s) ...

  3. Spark之SparkSql

    -- Spark SQL 以编程方式指定模式 val sqlContext = new org.apache.spark.sql.SQLContext(sc) val employee = sc.te ...

  4. springboot读取本地项目文件

    在读取springBoot+gradle构建的项目时,如果使用传统的FileInputStream读取文件流或者ResourceUtils工具类的方式 File file= ResourceUtils ...

  5. 前端学习之Bootstrap学习

    一,Bootstrap简介 在前端世界,有个叫Bootstrap的家伙,,是twitter 开源出来的一套前端框架,利用Ta可以快速开发网站界面,它的特点就是比自己从头写简单,直观,方便,快捷,省劲. ...

  6. 使用Python终结“你是什么垃圾”的灵魂拷问!

    目录 0 引言 1 环境 2 需求分析 3 代码实现 4 后记 0 引言 纸巾再湿也是干垃圾?瓜子皮再干也是湿垃圾??最近大家都被垃圾分类折磨的不行,傻傻的你是否拎得清?

  7. memecached存放session数据

    memcached存放session 1.session数据需要频繁调用. 2.session数据不需要永久性的保存在服务端. 3.在集群中,可以将session存放在memcached中或者是在数据 ...

  8. Programming In Lua 第八章

    1, 也就是说,lua虽然会把代码预编译成中间码,以提高运行速度.但其会在程序运行过程中需要编译器,所以其仍然是解释型语言.loadfile会加载一个文件并将其编译成中间码,并返回一个函数. 2, 3 ...

  9. 使用CocoaPods创建自己的私有库-iOS组件化第一步

    目前iOS组件化常用的解决方案是Pod+路由+持续集成,通常架构设计完成后第一步就是将原来工程里的模块按照架构图分解为一个个独立的pod工程(组件),今天我们就来看看如何创建一个Pod私有库. 新建: ...

  10. c#基础三

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...