Y服务-你真的懂 Yaml 吗?

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

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

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

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

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

使用Xml来表示一些模板

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

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

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

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

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

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

一、什么是Yaml

来自百科的定义:

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

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

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

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

environments:dev:url:

这段语法等价的Properties为:

=

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

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

大小写敏感

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

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

使用#开头作为注释行

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

对比Properties

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

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

对比Json

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

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

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

关于Yaml的定义可以访问下面的地址:

二、Yaml的语法

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

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

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

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

对象如何表示

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

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

数组如何表示

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

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

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

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

其中,日期、时间使用的是ISO8601国际标准格式,关于它的定义可以参考:

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

比如:

text:|HelloWorld

对应的结果为:

{text:'Hello\nWorld\n'}

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

text1:|+Hellotext2:|-Hello

对应的结果为:

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

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

三、操作Yaml


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

SpringBoot官方文档也介绍了整合该框架的方式,参考下面的地址:

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

A.引入框架

在Maven的文件中添加:

/groupIdartifactIdsnakeyaml//version/depency

B.代码片段

实现加载配置文件

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

InputStreaminputStream=().getResourceAsStream("");Yamlyaml=newYaml();MapString,ObjectobjectMap=(inputStream);(("path"));

实现对象转换

定义如下的Pojo对象:

publicstaticclassA{privateStringname="hello";privateListBbs=newArrayListB();publicStringgetName(){returnname;}publicvoidsetName(Stringname){=name;}publicListBgetBs(){returnbs;}publicvoidsetBs(ListBbs){=bs;}}publicstaticclassB{privateStringid=().toString();publicStringgetId(){returnid;}publicvoidsetId(Stringid){=id;}}

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

Aa=newA();().add(newB());().add(newB());Yamlyaml=newYaml();StringaString=(a);(aString);

输出结果如下:

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

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

Aa1=newYaml().parseToObject(aString,);

C.完整案例

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

publicclassYamlUtil{/***从资源文件加载内容,并解析为Map对象**@parampath*@return*/publicstaticMapString,ObjectloadToMap(Stringpath){if((path)){();}InputStreaminputStream=().getResourceAsStream(path);Yamlyaml=newYaml();MapString,ObjectobjectMap=(inputStream);returnobjectMap;}/***将字符串解析为Map对象**@paramcontent*@return*/publicstaticMapString,ObjectparseToMap(Stringcontent){if((content)){();}Yamlyaml=newYaml();MapString,ObjectobjectMap=(content);returnobjectMap;}/***将字符串解析为类对象**@paramcontent*@paramclazz*@paramT*@return*/publicstaticTTparseToObject(Stringcontent,ClassTclazz){if((content)||clazz==null){returnnull;}Yamlyaml=newYaml(newConstructor(clazz));Tobject=(content);returnobject;}/***格式化对象**@paramobject*@return*/publicstaticStringformat(Objectobject){Yamlyaml=newYaml();(object);}}

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

免责声明:本文章如果文章侵权,请联系我们处理,本站仅提供信息存储空间服务如因作品内容、版权和其他问题请于本站联系