前言
最近在学习微服务和Spring Cloud开发相关知识,在Spring Boot中,推荐使用properties或者YAML文件来完成配置,所以一开始学习使用的配置文件是properties文件,但是properties文件在表示层级关系和结构关系的方面有所欠缺,对于复杂的数据结构,YAML文件表示的清晰度会远远大于properties文件,所以我们使用YAML文件完成Spring Cloud的配置。
properties文件:
1 | server.port: 8761 |
YAML文件:
1 | server: |
由上面两个文件对比可以看出,在处理层级关系的时候,properties文件需要使用路径来描述层级,尽管前缀相同的路径也需要重复书写,YAML文件使用缩进的方式表示层级关系,更加清晰明了。
写这篇总结的初衷是在公司刚开始使用微服务架构的过程中,上线部署的时候由于YAML配置文件写错了而导致上线过程很不顺利,这件事一方面提醒我们YAML文件校验工具的重要性(STS自带的yedit插件就挺好用的),另一方面对于YAML语法的理解也非常重要,希望通过总结能够将YAML的语法理解得更加深入,尽量避免犯错误。
简介
YAML (YAML Ain’t Markup Language)语言(发音 /ˈjæməl/ )是一种简洁的非标记语言,YAML的设计目标,就是方便人类读写,YAML以数据为中心,使用空白、缩进、分行组织数据,使数据更加简洁易读。它实质上是一种通用的数据串行化格式。它的基本语法如下:
大小写敏感
使用缩进代表层级关系
缩进只能使用空格,不能使用Tab
缩进空格的个数没有要求,同一层级的元素左对齐即可(一般2或4个空格)
使用#表示注释
字符串可以不加引号进行标注
语法
学习YAML的时候可以在JS-YAML在线示例进行在线练习。
映射
YAML使用”: “(冒号加空格,记住一定要有空格)来表示每一个key: value
对:
1 | key: value |
使用缩进代表层级关系:
1 | key: |
YAML还支持流式(flow)语法表示对象:
1 | key: {child1: value1, child2: value2} |
较为复杂的对象格式,可以使用”? “(问号加空格)代表一个复杂的key,配合”: “(冒号加空格)代表一个value:
1 | ? |
代表[complexkey1, complexkey2]: [complexvalue1, complexvalue2]
,也就是属性为[complexkey1, complexkey2]
,值为[complexvalue1, complexvalue2]
。
数组
用”- “(短横线加空格)表示数组的一个元素:
1 | American: |
还可以这么写:
1 | - |
这个可以理解为:[[Boston Red Sox, Detroit Tigers, New York Yankees]]
,即数组元素也为数组。更加复杂的表示方法,如:
1 | persons: |
其流式表示(flow style
)为:
1 | persons: [{name: Mark McGwire, hr: 65, avg: 0.278}, {name: Sammy Sosa, hr: 63, avg: 0.288}] |
常量
YAML提供的常量包括:
整数(int)
浮点数(float)
字符串(str)
NULL(null)
日期(date)
时间(datetime)
布尔(boolean)
参考下面的例子可以快速熟悉YAML中常量的使用:
1 | booleans: |
上述例子的JSON表示法为:
1 | { boolean: [ true, false ], |
常用特殊符号
---
YAML可以在同一个文件中,使用
---
表示一个文档的开始;比如Spring Boot中application.yml的定义:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28spring:
application:
name: microservice-discovery-eureka-ha
---
spring:
# 指定profile=peer1
profiles: peer1
server:
port: 8761
eureka:
instance:
# 指定当profile=peer1时,主机名是peer1
hostname: peer1
client:
serviceUrl:
# 将自己注册到peer2这个Eureka上面去
defaultZone: http://peer2:8762/eureka/
---
spring:
profiles: peer2
server:
port: 8762
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1:8761/eureka/代表定义了两个profile(peer1、peer2),也可以用来分割不同的内容,比如记录日志:
1
2
3
4
5
6
7
8
9
10---
Time: 2018-12-23T19:02:31+08:00
User: ed
Warning:
This is an error message for the log file
---
Time: 2018-12-23T19:05:21+08:00
User: ed
Warning:
A slightly different error message....
与---
两个符号一起使用在一个配置文件中代表一个文件的结束:
1
2
3
4
5
6
7
8
9
10---
time: 20:03:20
player: Sammy Sosa
action: strike (miss)
...
---
time: 20:03:47
player: Sammy Sosa
action: grand slam
...相当于在一个YAML文件中连续写了两个YAML配置项。
!!
使用
!!
进行强制类型转换:1
2
3string:
- !!str 1234
- !!str false允许转换的类型很多:
1
2
3
4
5--- !!set
- Mark McGwire: 65
- Sammy Sosa: 63
- Sammy Sosa: 63
- Ken Griffy: 58set
类型表示:1
2
3
4
5
6
7# set类型
baseball players: !!set
? Mark McGwire
? Sammy Sosa
? Ken Griffey
# 流式表示
baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees }>
和|
>
在字符串中折叠换行,| 保留换行符,这两个符号在YAML中较为常见,比如:1
2
3
4
5
6accomplishment: >
Mark set a major league
home run record in 1998.
stats: |
65 Home Runs
0.278 Batting Average结果为:
1
2
3accomplishment=Mark set a major league home run record in 1998.
stats=65 Home Runs
0.278 Batting Average,注意:两个符号前面都要有空格,每行文本的前面也要有空格
|
符号常见用于在YAML中配置HTML片段:1
2
3
4phraseTemplate: |
<p style="color: red">
some template ${msg}
</p>引用
重复的内容在YAML中可以使用
&
来完成锚点定义,使用*
来完成锚点引用,例如:1
2
3
4
5
6hr:
- Mark McGwire
- &SS Sammy Sosa
rbi:
- *SS
- Ken Griffey可以看到,在
hr
中,使用&SS
为Sammy Sosa
设置了一个锚点(引用),名称为SS
,在rbi
中,使用*SS
完成了锚点使用,那么结果为:1
{hr=[Mark McGwire, Sammy Sosa], rbi=[Sammy Sosa, Ken Griffey]}
也可以这样定义:
1
2
3
4
5
6
7SS: &SS Sammy Sosa
hr:
- Mark McGwire
- *SS
rbi:
- *SS
- Ken Griffey注意,不能独立的定义锚点,比如不能直接这样写:
&SS Sammy Sosa
;另外,锚点能够定义更复杂的内容,比如:1
2
3
4default: &default
- Mark McGwire
- Sammy Sosa
hr: *defaulthr
相当于引用了default
的数组。注意,hr: *default
要写在同一行。
<<
合并内容。主要和锚点配合使用,可以将一个锚点内容直接合并到一个对象中。示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17merge:
- &CENTER { x: 1, y: 2 }
- &LEFT { x: 0, y: 2 }
- &BIG { r: 10 }
- &SMALL { r: 1 }
sample1:
<<: *CENTER
r: 10
sample2:
<< : [ *CENTER, *BIG ]
other: haha
sample3:
<< : [ *CENTER, *BIG ]
r: 100在
merge
中,定义了四个锚点,分别在sample
中使用。
sample1
中,<<: *CENTER
意思是引用{x: 1,y: 2}
,并且合并到sample1
中,那么合并的结果为:1
sample1={r=10, y=2, x=1}
sample2
中,<<: [*CENTER, *BIG]
意思是联合引用{x: 1,y: 2}
和{r: 10}
,并且合并到sample2
中,那么合并的结果为:1
sample2={other=haha, x=1, y=2, r=10}
sample3
中,引入了*CENTER
,*BIG
,还使用了r: 100
覆盖了引入的r: 10
,所以sample3
值为:1
sample3={r=100, y=2, x=1}
有了合并,我们就可以在配置中,把相同的基础配置抽取出来,在不同的子配置中合并引用即可。
参考资料
https://www.jianshu.com/p/97222440cd08
https://blog.csdn.net/vincent_hbl/article/details/75411243
https://blog.csdn.net/michaelhan3/article/details/69664932/