美文网首页
Datax有意思的配置类Configuration

Datax有意思的配置类Configuration

作者: 我不懂我不懂a | 来源:发表于2020-07-29 00:06 被阅读0次

datax的配置文件是json格式的,作为参数传递给datax.py运行。

python datax.py {YOUR_JOB.json}

datax将其抽象为Configuration类。
在Configuration的java doc中有这段描述:

 * Configuration 存在两种较好地实现方式<br>
 * 第一种是将JSON配置信息中所有的Key全部打平,用a.b.c的级联方式作为Map的Key,内部使用一个Map保存信息 <br>
 * 第二种是将JSON的对象直接使用结构化树形结构保存<br>
 * <p/>
 * 目前使用的第二种实现方式,使用第一种的问题在于: <br>
 * 1. 插入新对象,比较难处理,例如a.b.c="bazhen",此时如果需要插入a="bazhen",也即是根目录下第一层所有类型全部要废弃
 * ,使用"bazhen"作为value,第一种方式使用字符串表示key,难以处理这类问题。 <br>
 * 2. 返回树形结构,例如 a.b.c.d = "bazhen",如果返回"a"下的所有元素,实际上是一个Map,需要合并处理 <br>
 * 3. 输出JSON,将上述对象转为JSON,要把上述Map的多级key转为树形结构,并输出为JSON <br>

有意思的是,Configuration类可以通过json的key路径来访问值:

     * 根据用户提供的json path,寻址具体的对象。
     * <p/>
     * <br>
     * <p/>
     * NOTE: 目前仅支持Map以及List下标寻址, 例如:
     * <p/>
     * <br />
     * <p/>
     * 对于如下JSON
     * <p/>
     * {"a": {"b": {"c": [0,1,2,3]}}}
     * <p/>
     * config.get("") 返回整个Map <br>
     * config.get("a") 返回a下属整个Map <br>
     * config.get("a.b.c") 返回c对应的数组List <br>
     * config.get("a.b.c[0]") 返回数字0

我们来看看是怎么做到的。

Configuration依赖了fastjson,将json配置文件存储在一个对象 root中:

    private Object root = null;
    ......
    private Configuration(final String json) {
        try {
            this.root = JSON.parse(json);
        } catch (Exception e) {
            throw DataXException.asDataXException(CommonErrorCode.CONFIG_ERROR,
                    String.format("配置信息错误. 您提供的配置信息不是合法的JSON格式: %s . 请按照标准json格式提供配置信息. ", e.getMessage()));
        }
    }

我们可以通过get(path)输入一个路径来访问对应的值。例如a.b.c[0]
a.b.c[0]会被解析成 ["a", "b", "c", "[0]"]的数组。

看下面的代码,each就是["a", "b", "c", "[0]"]的项,遍历到a时,就从root取出a的值,直到遍历到“[0]”,target为一个List,则从一个列表中取值。

    private Object findObject(final String path) {
        boolean isRootQuery = StringUtils.isBlank(path);
        if (isRootQuery) {
            return this.root;
        }

        Object target = this.root;

        for (final String each : split2List(path)) {
            if (isPathMap(each)) {
                target = findObjectInMap(target, each);
                continue;
            } else {
                target = findObjectInList(target, each);
                continue;
            }
        }

        return target;
    }

    @SuppressWarnings("unchecked")
    private Object findObjectInMap(final Object target, final String index) {
        boolean isMap = (target instanceof Map);
        if (!isMap) {
            throw new IllegalArgumentException(String.format(
                    "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象,但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.",
                    index, target.getClass().toString()));
        }

        Object result = ((Map<String, Object>) target).get(index);
        if (null == result) {
            throw new IllegalArgumentException(String.format(
                    "您提供的配置文件有误. 路径[%s]值为null,datax无法识别该配置. 请检查您的配置并作出修改.", index));
        }

        return result;
    }

    @SuppressWarnings({ "unchecked" })
    private Object findObjectInList(final Object target, final String each) {
        boolean isList = (target instanceof List);
        if (!isList) {
            throw new IllegalArgumentException(String.format(
                    "您提供的配置文件有误. 路径[%s]需要配置Json格式的Map对象,但该节点发现实际类型是[%s]. 请检查您的配置并作出修改.",
                    each, target.getClass().toString()));
        }

        String index = each.replace("[", "").replace("]", "");
        if (!StringUtils.isNumeric(index)) {
            throw new IllegalArgumentException(
                    String.format(
                            "系统编程错误,列表下标必须为数字类型,但该节点发现实际类型是[%s] ,该异常代表系统编程错误, 请联系DataX开发团队 !",
                            index));
        }

        return ((List<Object>) target).get(Integer.valueOf(index));
    }


    private boolean isPathMap(final String path) {
        return StringUtils.isNotBlank(path) && !isPathList(path);
    }

相关文章

网友评论

      本文标题:Datax有意思的配置类Configuration

      本文链接:https://www.haomeiwen.com/subject/qwdcrktx.html