zoukankan      html  css  js  c++  java
  • YAML配置解析

    引子

    “事件处理业务的简易组件编排框架” 中,讲到了事件处理流程的组件编排,是通过枚举来实现事件处理流程的配置的。实际应用中,可以采用 YAML 文件来配置。

    YAML 是一种主流的配置文件语法。相比 XML,形式上更为简洁;相比 JSON, 去掉了引号之繁琐;相比扁平的 properties,能够表达更复杂的结构。本文来学习 YAML 语法和解析。


    基础知识

    • 大小写敏感
    • YAML 通过缩进来标识数据或属性之间的层级;
    • 缩进时不允许使用Tab键,只允许使用空格;
    • 同一缩进的属性,是上一层的同一对象的平级属性;
    • 数组元素,以“缩进 - ” 表示;
    • # 表示注释,从这个字符一直到行尾,都会被解析器忽略。

    YAML 支持的数据结构有三种:

    • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
    • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
    • 纯量(scalars):单个的、不可再分的值

    可参考: “YAML语法介绍”


    基本结构

    如下所示,是一个典型的 YML 配置(eventflow_finished.yml):

    
    bizTypes:
      - 'docker_bounce_shell'
    eventType: 'create'
    eventSourceType: 'bizEvent'
    eventflowClassName: 'cc.lovesq.eventflow.demo.DefaultEventFlow'
    model: 'eventflow'
    way: 'serial'
    originParamType: 'cc.lovesq.eventflow.demo.DefaultEventData'
    componentParamType: 'cc.lovesq.eventflow.demo.DefaultFlowContext'
    components:
      - 'notificationSender_common'
      - 'defaultBigDataSender'
      - 'cc.lovesq.eventflow.demo.components.DefaultBigDataSender'
    
    

    要解析这个配置,需要建立相应的对象模型,就像将 JSON 字符串转换成 Java 对象一样。这个对象 EventFlowExecutionModel 也不难建立:

    
    public class EventFlowExecutionModel extends ComponentsExecutionModel {
    
        /**
         * 事件流程处理的业务类型,比如反弹shell, 本地提权等
         * 由于一个通用事件处理流程可以处理多个业务类型,因此这里可以是列表
         */
        private List<String> bizTypes;
    
        /** 事件类型,比如创建,更新等 */
        private String eventType;
    
        /** 事件流程处理的事件源类型,比如 agent上报事件, bizEvent事件 */
        private String eventSourceType;
    
        /** 根据类名来选择事件处理流程实例 */
        private String eventflowClassName;
    
        /** eventflow 事件流程处理(不指定默认)  components 有序组件集执行 */
        private ExecutionModel model = ExecutionModel.eventflow;
    
        /** 原始传入事件处理流程的入口参数类型 */
        private String originParamType;
    
        /** serial 串行(不指定默认)  parallel 并发 */
        protected ExecWay way = ExecWay.serial;
    
        /** 组件参数类型 */
        protected String componentParamType;
    
        protected List<String> components;
    
        // getter/ setter
    }
    
    

    使用 snakeyaml 解析:

    
    public class ConfigUtil {
    
        /**
         * 通过 yml 文件加载组件执行模型对象
         */
        public static EventFlowExecutionModel load(String ymlFilePath) {
            return load(ymlFilePath, EventFlowExecutionModel.class);
        }
    
        /**
         * 通过 yml 文件加载对象模型
         */
        public static <T> T load(String ymlFilePath, Class<T> cls) {
            Yaml yaml = new Yaml();
            T model = yaml.loadAs(cls.getClassLoader().getResourceAsStream(ymlFilePath), cls);
            return model;
        }
    
    }
    
    

    需要引入依赖:

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

    编写单测:

    
    public class ConfigUtilTest extends CommonForAssert {
    
        @Test
        public void testLoad() {
            EventFlowExecutionModel eventFlowExecModel = ConfigUtil.load("eventflow_finished.yml");
            eq(Arrays.asList("docker_bounce_shell"), eventFlowExecModel.getBizTypes());
            eq("cc.lovesq.eventflow.demo.DefaultEventFlow", eventFlowExecModel.getEventflowClassName());
            eq(ExecutionModel.eventflow, eventFlowExecModel.getModel());
            eq(ExecWay.serial, eventFlowExecModel.getWay());
            eq("cc.lovesq.eventflow.demo.DefaultEventData", eventFlowExecModel.getOriginParamType());
            eq("cc.lovesq.eventflow.demo.DefaultFlowContext", eventFlowExecModel.getComponentParamType());
            eq(Arrays.asList("notificationSender_common", "defaultBigDataSender", "cc.lovesq.eventflow.demo.components.DefaultBigDataSender"), eventFlowExecModel.getComponents());
        }
    }
    

    支持多个事件处理流程

    实际应用中,显然需要在一个文件里支持多个事件处理流程。 如下所示(eventflow.yml):

    
    version: 1.0
    flows:
    
      - bizTypes:
        - 'docker_bounce_shell'
        - 'abnormal_login'
        eventType: 'create'
        eventSourceType: 'bizEvent'
        eventflowClassName: 'cc.lovesq.eventflow.demo.DefaultEventFlow'
        model: 'eventflow'
        way: 'serial'
        originParamType: 'cc.lovesq.eventflow.demo.DefaultEventData'
        componentParamType: 'cc.lovesq.eventflow.demo.DefaultFlowContext'
        components:
        - 'notificationSender_common'
        - 'defaultBigDataSender'
        - 'cc.lovesq.eventflow.demo.components.DefaultBigDataSender'
    
      - bizTypes:
        - 'local_rights'
        - 'docker_local_rights'
        eventType: 'create'
        eventSourceType: 'bizEvent'
        eventflowClassName: 'cc.lovesq.eventflow.demo.DefaultEventFlow'
        model: 'eventflow'
        way: 'serial'
        originParamType: 'cc.lovesq.eventflow.demo.DefaultEventData'
        componentParamType: 'cc.lovesq.eventflow.demo.DefaultFlowContext'
        components:
        - 'notificationSender_common'
        - 'defaultBigDataSender'
    
    

    相应的,也要建立对应的 Java 对象模型:

    
    public class EventFlowsModel {
    
        private String version;
    
        private List<EventFlowExecutionModel> flows;
    
        // getter / setter
    }
    
    

    锚点与引用

    在配置文件 eventflow.yml 中,除了 bizTypes 和 components ,中间的基本都是重复配置。yaml 支持通过锚点 &config 和引用 <<: *config 来引用重复配置。如下所示(eventflow_brief.yml):

    
    version: 1.0
    
    flows:
    
      - bizTypes:
        - 'docker_bounce_shell'
        - 'abnormal_login'
        commonConfig: &commonConfig
          eventType: 'create'
          eventSourceType: 'bizEvent'
          eventflowClassName: 'cc.lovesq.eventflow.demo.DefaultEventFlow'
          model: 'eventflow'
          way: 'serial'
          originParamType: 'cc.lovesq.eventflow.demo.DefaultEventData'
          componentParamType: 'cc.lovesq.eventflow.demo.DefaultFlowContext'
        components:
        - 'notificationSender_common'
        - 'defaultBigDataSender'
        - 'cc.lovesq.eventflow.demo.components.DefaultBigDataSender'
    
      - bizTypes:
        - 'local_rights'
        - 'docker_local_rights'
        commonConfig:
          <<: *commonConfig
        components:
        - 'notificationSender_common'
        - 'defaultBigDataSender'
    
    

    对应的 Java 对象为:

    
    public class CommonConfig {
    
        /** 事件类型,比如创建,更新等 */
        private String eventType;
    
        /** 事件流程处理的事件源类型,比如 agent上报事件, bizEvent事件 */
        private String eventSourceType;
    
        /** 根据类名来选择事件处理流程实例 */
        private String eventflowClassName;
    
        /** eventflow 事件流程处理(不指定默认)  components 有序组件集执行 */
        private ExecutionModel model = ExecutionModel.eventflow;
    
        /** 原始传入事件处理流程的入口参数类型 */
        private String originParamType;
    
        /** serial 串行(不指定默认)  parallel 并发 */
        protected ExecWay way = ExecWay.serial;
    
        /** 组件参数类型 */
        protected String componentParamType;
    
        // getter / setter
    }
    
    public class EventFlowExecutionModelRefCommon {
    
        private List<String> bizTypes;
    
        private CommonConfig commonConfig;
    
        private List<String> components;
    
        // getter / setter
    }
    
    public class EventFlowsModelRefCommon {
    
        private String version;
    
        private List<EventFlowExecutionModelRefCommon> flows;
    
        // getter / setter
    }
    
    

    这里的诀窍就是:建立与 yml 文件里对应的模型,就像 JSON 对象解析类似。


  • 相关阅读:
    用javascript写星际飞机大战游戏
    Vue源码分析之实现一个简易版的Vue
    Vue源码分析之数据驱动
    Vue源码分析之虚拟DOM
    使用HbuilderX离线打包5+APP
    ERROR in build.js from UglifyJs
    PHP 的一些开发规范
    Markdown使用TOC自动生成导航栏
    Hexo博客skapp主题部署填坑指南
    Docker 官方安装详解
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/14683035.html
Copyright © 2011-2022 走看看