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 對象解析類似。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM