最近在学 Storm 的时候发现 Storm 的配置文件是 yaml 格式的,就好奇地查了下这个没听说过的格式(YAML - Wikipedia),这才发现原来不是什么新新物种,而是 2001 年就推出来了的文件格式。虽然 Yaml 相对于 XML 这种老大哥还差远了,但是后辈小子胜在年轻,有干劲,语法简单,功能强大,而且这几年相关工具的解析速度也提升了不少,大有超越 XML 这种大块头的趋势。简单地试用了下,发现压马路(“yaml”的拼音打出来就是这个)的语法真的是既简洁又优雅,让人爱不释手。于是,就这么愉快地决定了,以后的项目中没有其他要求的情况下全部使用 yaml 来做格式化,让 XML 先飞一会儿……

言归正传,Google 了一下,评价最好的解析工具还是 snakeyaml:

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.15</version>
</dependency>

对于下面这样基本的配置文件:

redis.host: rhost
redis.port: 6379
parse.rule:
    - light
    - weighted

使用 snakeyaml 解析 yaml 配置文件非常简单:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public static Map<String, Object> loadMap(String file) throws IOException {
    Yaml yaml = new Yaml();
    Map<String, Object> map = null;
    InputStream is = YamlUtil.class.getResourceAsStream(file);
    if (is != null) {
        map = (Map<String, Object>) yaml.load(is);
        is.close();
    }
    return map;
}

对于下面这样比较复杂的对象 dump 文件:

!!me.weyo.yaml.Dev {
  enabled: false,
  inn: {name: III, timeout: 600000000},
  port: 33333,
  type: T1
}
--- !!me.weyo.yaml.Dev { 
  enabled: true,
  inn: {name: UH, timeout: 180003300},
  port: 10028,
  type: T2
}

也可以很轻松的解析:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public static List<Object> loadObjects(String file) throws IOException {
    Yaml yaml = new Yaml();
    List<Object> list = null;
    InputStream is = YamlUtil.class.getResourceAsStream(file);
    if (is != null) {
        list = new ArrayList<Object>();
        for (Object obj : yaml.loadAll(is)) {
            list.add(obj);
        }
        is.close();
    }
    return list;
}

当然,如果有需要,还可以将对象 dump 到文件中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Yaml yaml = new Yaml();
RedisConnection redis = new RedisConnection();
redis.setHost("rh134");
redis.setPort(10029);

FileWriter output = null;
try {
    output = new FileWriter("src/main/resources/topology.yaml");
} catch (IOException e) {
    e.printStackTrace();
}
if (output != null)
    yaml.dump(redis, output);
output.close();

综上所述,无所不能的 Yaml 真是居家旅行之必备 :)


Q & A

无法创建 Java 对象

Exception in thread "main" Can't construct a java object for tag:yaml.org,2002:me.weyo.yaml.Dev; exception=java.lang.NoSuchMethodException: me.weyo.yaml.Dev.<init>()
 in 'reader', line 1, column 1:
    !!me.weyo.yaml.Dev ... 
    ^

这个错误表明被解析的对象(Dev)中没有默认的构造器(即只有带参数的构造器,没有无参构造器,snakeyaml 无法将对象解析为 Bean)。

解析错误异常

Exception in thread "main" while parsing a flow mapping
 in 'reader', line 1, column 40:
     ... me.weyo.yaml.Dev {
                                         ^
expected ',' or '}', but got Value
 in 'reader', line 3, column 7:
      port: 33333
          ^

这是被解析的文件中有属性没有以逗号结束的缘故,例如,下面这样的文件描述就少了逗号:

# 错误的配置方式!
!!me.weyo.yaml.Dev {
  enabled: false # 缺少逗号
  inn: {name: III, timeout: 600000000}
  port: 33333
  type: T1
}

标记识别异常

Exception in thread "main" expected '<document start>', but found Tag
 in 'reader', line 6, column 1:
    !!me.weyo.yaml.Dev ... 
    ^

这是由于缺少不同对象之间的分隔标识,例如这样的定义:

# 错误的配置方式!
!!me.weyo.yaml.Dev {
  enabled: false,
  inn: {name: III, timeout: 600000000},
  port: 33333,
  type: T1
}
!!me.weyo.yaml.Dev { # 缺少分隔符
  enabled: true,
  inn: {name: UH, timeout: 180003300},
  port: 10028,
  type: T2
}



Comments

comments powered by Disqus