MrRobot5 生也有涯,知也无涯

Yaml in Spring Boot


起因

在使用 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 基本概念

Processing YAML Information

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());

第三方库实现针对规范中的定义进行了具体的实现,对功能进行了清晰明确的划分。


Similar Posts

Content