在Java 的世界裏,配置的事情都交給了 Properties,要追溯起來這個模塊仍是從古老的JDK1.0 就開始了的。java
"天哪,這但是20年前的東西了,我竟然還在用 Properties.."正則表達式
然而,本文的主角並非Properties,而是Yaml。這是新時代裏微服務架構上的寵兒,和 Properties 相比起來,Yaml 顯得有些弄潮兒。
以往的大多數項目裏,咱們均可以發現 Properties配置文件的蹤影,這包括用做業務屬性配置的、機機接口交互的、國際化的等等用途。
而少許的一些狀況下,也存在一些"混合式"的作法,好比:spring
混雜的配置方式每每出如今一些充滿"壞味道"的項目裏頭,由於代碼陳舊、斯人已矣 等緣由,很難造成統一的方式。
然而,除開 Properties 屬性文件這種簡單的配置方式以外,採用其餘的方法不外乎都是爲了適應配置複雜、多元化的訴求。編程
那麼,Yaml 就是應對這種場景而產生的,在 SpringBoot 的官方文檔中,有很多篇幅是 使用了 Yaml 語法的配置格式。
下面介紹一下 Yaml 以及它是如何使用的。數組
來自百科的定義:
"Yaml 是一個可讀性高,易用的數據序列化格式,由 Clark Evans 在2001年首次發表。"
可見 Yaml 並非一個很新的東西,只是在之前接觸的人很少罷了。此外,Yaml也被各類編程語言及框架所支持, 通用性很高。
在Java體系中,通常的微服務框架都支持甚至優先推薦使用 Yaml 做爲首選的配置語言。springboot
而 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 相對來講更加的結構化,更適合用來表達一個對象。
它在語法上有這樣的特色:dom
對比 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 是很是簡單的, 它所定義的元素只有三個:
對象如何表示
一個對象的屬性、嵌套關係經過空格縮進對齊來表示,以下:
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 的經常使用組件是 Snake Yaml,這個庫支持標準的 Yaml 1.1 版本。
SpringBoot 官方文檔也介紹了整合該框架的方式,參考下面的地址:
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-loading-yaml
下面提供 將SnakeYaml 整合到項目的樣例。
在Maven的pom.xml文件中添加:
<dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>1.21</version> </dependency>
實現加載配置文件
以下面的代碼,實現了從類路徑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); ...
最終,咱們能夠將 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