起因
在使用 Spring Boot 配置工程时,发现并没有按照预期解析。疑问:是yaml 的解析规则还是 Spring Boot 解析规则?
# yaml 配置
alias:
  52: s52-online
# springboot 解析完成的key-value
# alias[52] -> s-52-online
Spring Boot 对yaml properties的处理
/**
 * YamlProcessor to create a Map containing the property values.
 * @see org.springframework.boot.env.YamlPropertySourceLoader.Processor#process
 */
public Map<String, Object> process() {
    final Map<String, Object> result = new LinkedHashMap<String, Object>();
    process(new MatchCallback() {
        // loadYaml完成后的object 强制转换为 map数据结构
        public void process(Properties properties, Map<String, Object> map) {
            // 拍平map数据结构,最终得到的是 property values
            result.putAll(getFlattenedMap(map));
        }
    });
    return result;
}
首先,processor 会针对yaml 读取完的结果进行处理,主要就是把number keys 转为string keys。
// 得到的数据:{alias={[52]=s-52-online}}
private Map<String, Object> asMap(Object object) {
    // YAML can have numbers as keys
    for (Entry<Object, Object> entry : map.entrySet()) {
        Object key = entry.getKey();
        if (key instanceof CharSequence) {
            result.put(key.toString(), value);
        }
        else {
            // It has to be a map key in this case
            result.put("[" + key.toString() + "]", value);
        }
    }
    return result;
}
然后,再把map 拍平,得到最终的the property values。
private void buildFlattenedMap(Map<String, Object> source, String path) {
    for (Entry<String, Object> entry : source.entrySet()) {
        String key = entry.getKey();
        if (StringUtils.hasText(path)) {
            // 针对上述number keys的key,直接追加到path,得到的就是 alias[52]
            if (key.startsWith("[")) {
                key = path + key;
            }
            else {
                key = path + '.' + key;
            }
        }
        // ... value 拍平处理,理论上只有String, Map, Collection
    }
}
yaml 文件读取浅析
yaml 是一种文件格式的规范,YAML Version 1.1。
java 读取yaml使用到的第三方库:snakeyaml。SnakeYAML Engine Documentation。
snakeyaml 是根据YAML规范实现的。
YAML 基本概念
Representation Graph相关:
Nodes: YAML nodes have content of one of three kinds: scalar, sequence, or mapping.
处理相关:
Parse : Parsing is the inverse process of presentation, it takes a stream of characters and produces a series of events.
Compose : Composing takes a series of serialization events and produces a representation graph.
Construct : The final input process is constructing native data structures from the YAML representation.
snakeyaml 关键实现
// yaml load file
new Composer(new ParserImpl(new StreamReader(new UnicodeReader(input))), new Resolver());
第三方库实现针对规范中的定义进行了具体的实现,对功能进行了清晰明确的划分。