聊聊我寫Yml的親身感受
本文轉載自微信公眾號「小姐姐味道」,作者小姐姐養(yǎng)的狗。轉載本文請聯(lián)系小姐姐味道公眾號。
我非常羞恥的發(fā)現(xiàn),配置文件界,已經(jīng)被下面三種所統(tǒng)治:yaml,toml和json,這讓一直使用properties文件的javaer深深的埋下了頭。
不要擔心,當你讀到文章最后,你也會羞愧的埋下頭。也可能會有一絲憤怒。
像各種人工智能調(diào)參數(shù),k8s調(diào)參師,都已經(jīng)成功升級為yml配置大師。作為一個常年使用yml文件的SpringBoot框架使用者,有時候?qū)ml的表現(xiàn)形式竟然顯露出了困惑,這不由得讓人羞愧又加了一層。
YAML,竟然是XML的一個子集,所以它的復雜是有源頭的,最早誕生于2009年。
使用yml文件,首先遇到的問題,就是它的縮進問題。就如同python語言一樣,yml文件的表現(xiàn)層次,是靠嵌套的縮進來完成的。它并不使用TAB,而是使用空格表示縮進。
要命的是,空格的多少,并不重要,只要相同級別元素左側能夠?qū)R就行。這對于CV黨來說,不得不說是一個噩夢哈哈。
那一個配置文件,要解決哪些問題呢?Redis已經(jīng)做出了回答。就像你學習一門新的語言一樣,解決了它的字符串和集合的表示方法,基本上寫代碼就沒問題了。那我們就挨個來看一下。
以下方法以SpringBoot的yml文件格式為準,其他場景的解析器會有些許差異。為了能夠debug這些值,我們簡單的寫了一個測試類,然后再設值完成之后打印以下就可以了。
- @EnableAutoConfiguration
- @Configuration
- public class TestConfig implements InitializingBean {
- @Value("${str1}")
- String str1;
- @Override
- public void afterPropertiesSet() throws Exception {
- System.out.println(this);
- }
- }
1. 字符串
字符串是最簡單的配置,也是最常見的配置。再spring中,字符串可以代引號,也可以不帶引號。所以下面三行的配置效果,是一樣的。
- str1: ksdfjsdlkfjdsf skdfljs
- str1: 'ksdfjsdlkfjdsf skdfljs'
- str1: "ksdfjsdlkfjdsf skdfljs"
那么,如何支持多行文本呢?畢竟有些需求,就是這么作死。寫法如下:
- str1: |
- ksdfjsdlkfjdsf skdfljs
- ksdfjsdlkfjdsf skdfljs
- ksdfjsdlkfjdsf skdfljs
注意,后面不需要有其他的畫蛇添足的結束表示,一切都是靠縮進來證明的。當然,你也可以把 |換成>,效果是一樣的。
- str1: >
- ksdfjsdlkfjdsf skdfljs
- ksdfjsdlkfjdsf skdfljs
- ksdfjsdlkfjdsf skdfljs
要命的是,它還有第三種寫法。
- str1: "ksdfjsdlkfjdsf skdfljs
- ksdfjsdlkfjdsf skdfljs
- ksdfjsdlkfjdsf skdfljs"
2. 數(shù)字
當我們的接收者,是一個數(shù)字的時候,比如下面這個。
- @Value("${a}")
- int a ;
那么,你即使把配置文件寫成了字符串,它也會強制轉成數(shù)字。
- a: "014"
此時,a的數(shù)值,就會被設置成整數(shù)14。
神奇的是,如果你把引號去掉,也就是下面這樣。
- a: 014
此時,a的數(shù)值,竟然變成了12!
我就曾碰到過這樣的極品bug,浪費了不少腦細胞,wtf。因為以0開頭,代表的是八進制,解析器中間做了一層轉換。所以,按照這個邏輯,0x14就是20,使用時一定要注意這一點。機靈的同學可以拿來埋坑哦。
這里也有一些特殊的寫法。
- float: 1.23e+3 # 浮點數(shù)
- fixed: 13.67 # 固定小數(shù)
- minmin: -.inf # 表示負無窮
- notNumber: .NaN # 無效數(shù)字
- boolean: [true, false] # 布爾值
- string: '12345' # 字符串
- date: 2021-06-03 # 日期
3. 字典
再來看一下常見的字典。其實,把所有的配置羅列開來,本身就是一個字典,也就是kv配置。
它是以:進行分割的,所以左半部分要求不能有特殊字符,否則就暈菜了。不不不,它沒有暈菜,因為它把亂七八糟的字符,正確的識別了出來。比如下面的yml配置。
- a&& xk@71: 0x14
這樣的代碼接收。
- @Value("${a&& xk@71}")
- int a ;
嗯,容易被打死的寫法。所以,你懂的。
還是我太幼稚了,yml文件根本就沒規(guī)定key不允許有特殊字符,它允許你這么做。
4. 對象
由字典,很容易可以擴展到對象。因為對象,也是一堆屬性的集合。json已經(jīng)證明,這些屬性,就是一堆KV,我們的yaml也是如此。
假設有如下的代碼,我們需要構造dog中的數(shù)據(jù)。
- @Data
- public static class Dog{
- private String xjjdog1;
- private String xjjdog2;
- }
- @Bean
- @ConfigurationProperties(prefix = "dog")
- public Dog getDog(){
- return new Dog();
- }
第一種yml的寫法,是這樣。
- dog:
- xjjdog1: i am xjjdog1
- xjjdog2: i am xjjdog1++
而另一種方式,是把json數(shù)據(jù)直接給寫到文件里。
- dog: {xjjdog1: 'i am xjjdog1',xjjdog2: 'i am xjjdog++'}
當然,多個層次,可以在一行之中平鋪開。比如prefix是super.dog,那么yml文件就可以這么寫。
- super.dog: {xjjdog1: 'i am xjjdog1',xjjdog2: 'i am xjjdog++'}
5. 列表支持
列表,就是list,我們可以使用數(shù)組接收,也可以使用List等。
它也有兩種寫法。這是最常見的一種。
- animal:
- - dog
- - cat
- - monkey
當然,也可以放在一行。
- animal: [dog,cat,monkey]
這沒什么問題,關鍵是yml文件支持嵌套。比如List里嵌套Map,或者Map里嵌套List。當嵌套層次比較深的時候,或者縮進沒什么規(guī)律的時候,就顯得非常的亂。
比如下面這個k8s的pod配置。
- apiVersion: v1
- kind: Pod
- metadata:
- name: xjjdog-Pod
- labels:
- app: front-web
- spec:
- containers:
- - name: front-web
- image: nginx
- ports:
- - containerPort: 80
- - name: front-app
- image: xjjdog/frontapp
- ports:
- - containerPort: 14000
- storages:
- ...
比較復雜的是spec,里面有containers、storages等配置。其中containers是一個列表,列表之間是一個map,map中其中的ports屬性,又是一個列表...如此嵌套,如果配置文件比較長的化,不熟悉業(yè)務屬性的同學就會容易暈菜。
6. 特殊數(shù)據(jù)
即使是這樣,yaml也比xml簡單的多。它也有很多特殊的寫法。
比如這個。
- str1: !!str 2021-06-03
它的意思是,把2021-06-04,強制轉化成字符串。這樣的強制轉化有很多,但大多數(shù)時候你不會用。但如果你想要把你的yaml文件變得復雜,讓別人不敢動,那就可以這么做。
- !!int # 整數(shù)類型
- !!float # 浮點類型
- !!bool # 布爾類型
- !!str # 字符串類型
- !!binary # 也是字符串類型
- !!timestamp # 日期時間類型
- !!null # 空值
- !!set # 集合
- !!omap, !!pairs # 鍵值列表或?qū)ο罅斜?nbsp;
- !!seq # 序列,也是列表
- !!map # 鍵值表
既然yml文件有這么多復雜的寫法,那么我們就可以去玩一把。比如下面的寫法。
- from: &d !!str 2021-06-04
- str1: *d
這個配置,和上面的配置,效果是一樣的,&的意思是標記,我們給它起了個名字,叫做d;*的意思是引用,我們在需要它的地方引用一把就可以了。
yml中的key,竟然也可以用對象或者復雜的結構作為key。為了標識是一個特殊的key,我們還要做一點處理。
- ?[blue, reg, green]: Color
上面這個配置的?,就是說,我下面要進行一個比較復雜的配置了,你準備好了么?
7. End
學會了這些招數(shù)的你,是不是躍躍欲試了?想要在你的SpringBoot項目里搞一點有意思的東西?為了讓你的基礎架構部門無法掃描出你的配置,為什么不呢?
這是我改造的一個普通datasource的配置文件。
- h2: &sa !!str sa
- driver: &driver !!str org.h2.Driver
- defaults: &defaults
- ?username: *sa
- ?password:
- ?driverClassName: *driver
- spring:
- datasource:
- <<: *defaults
- ?url: !!str >
- jdbc:h2:mem:h2test;
- DB_CLOSE_DELAY=-1;
- DB_CLOSE_ON_EXIT=FALSE
你覺得美么?我反正腿挺疼的。
作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎架構和Linux。十年架構,日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。我的個人微信xjjdog0,歡迎添加好友,進一步交流。