實戰項目:設計實現一個流程編排框架(設計)

上一篇文章我們講了《實戰項目:設計實現一個流程編排框架(分析)》主要對流程編排框架產生的背景,並做了需求分析,這其中包含功能性需求和非功能性需求,算是在正式開始設計之前做一個鋪墊。

前面提到,項目實戰分爲分析、設計、實現、測試幾個部分講解,其中分析環節跟面向對象分析很相似,都是做需求梳理。但是在時間項目中設計和實現就不是這麼一回事了這裏的“設計”指的是系統設計,主要是劃分模塊,對模塊進行設計。

我們主要分爲模型定義、流程加載、流程解析、集成使用這四個模塊,來說明編排框架的設計思路,今天講解的重點是,如何通過合理的設計,實現一個易用,易擴展,靈活,延遲低,高容錯等非功能需求的編排框架。

模型定義

框架需要定義出服務模型,包括請求參數、輸出參數、臨時變量,流程定義,節點定義,這幾個元素。

  • 請求參數:流程需要定義一個輸入參數的基類,在開發的過程中請求參數DTO需要繼承這個DTO;

  • 輸出參數:流程需要定義一個輸出參數的基類,在開發的過程中響應參數DTO需要繼承這個DTO;

  • 臨時變量:用於在流程執行過程中做上下文管理,包括EL表達式解析變量和流程之間參數扭轉;

  • 流程定義:需要定義流程標識ID用於標識流程,流程名稱用於定義流程別名,請求參數用於定義流程統一輸入DTO,輸出參數用於定義流程統一響應DTO,臨時變量用於上下文管理,流程描述用於描述整個流程的作用,流程節點用於所有節點以Map的形式保存;

  • 節點定義:需要定義節點ID用於標識節點,節點名稱用於定義節點別名,請求參數用於定義流程統一輸入DTO,輸出參數用於定義流程統一響應DTO,節點描述用於描述整個流程的作用,節點類型用於不同的節點類型包括方法節點、bean節點、服務節點、條件節點等,下一個節點標識用過遞歸的形式執行節點,組件內容,具體指向執行的節點。

這幾個模型直接的關係是怎麼樣的?整個流程模型是一個包含關係,流程定義 = 請求參數+輸出參數+臨時變量+節點定義+自定義屬性;節點定義 = 請求參數+輸出參數+自定義屬性;我們在日常開發的過程中需要定義請求參數和輸出參數分別集成請求參數和輸出參數的基類,通過配置文件加載流程定義,也就是說運行期階段我們只會用到流程定義模型。定義如下:

name: openAccount
id: test
desc: 條件執行
input: com.service.flow.sample.common.model.TestInput
output: com.service.flow.sample.common.model.TestOutput
temp: com.service.flow.sample.common.model.TestTemp
startNode: node1
nodes:
  - node:
      id: node1
      name: methodInvoke
      component: com.service.flow.sample.common.component.TestComponent:test1
      desc: 單節點執行
      input: com.service.flow.sample.common.model.TestInput
      type: method
      next: node2
  - node:
      id: node2
      name: beanInvoke
      component: testComponent:test2
      desc: 單節點執行
      input: com.service.flow.sample.common.model.TestInput
      type: bean
      next: node3
  - node:
      id: node3
      name: conditionByAge
      component: age>20:node4,age<20:node5
      desc: 單節點執行
      type: condition
  - node:
      id: node4
      name: beanInvoke
      component: testComponent:test4
      desc: 單節點執行
      input: com.service.flow.sample.common.model.TestInput
      type: bean
  - node:
      id: node5
      name: beanInvoke
      component: testComponent:test5
      desc: 單節點執行
      input: com.service.flow.sample.common.model.TestInput
      type: bean

流程加載

首先我們要確定流程的幾個來源有可能是定義的yml、properties、xml、json或者接口;那我我們設計就要支持流程模式可擴展,不管通過什麼方式初始化模型,只要能夠轉換成流程定義,不管什麼方式都是可以,完全用到可擴展的需求;

當然我們也會提供默認的流程加載方式,我們這裏以yml格式舉例,首先我們需要定義一個yml流程文件,示例如下,新增一個test.flow.yml文件,爲了考慮文件路徑自定義,也需要把掃描包做成可配置的功能,模式是classpath:flow/*.flow.yml;

平臺首先需要定義定一個流程註冊接口,所用加載流程模型用於實現流程註冊,在通過平臺的機制把流程模型加載到流程管理器,具體實現類我們需要對定義的yml流程就行解析,當然規範要嚴格按照yml的格式定義;在加載的過程中要有異常處理機制,比如定義的節點和參數不存在,重複定義流程;每一個模型的異常處理完全由平臺統一管控。

考慮到編寫流程文件的便利性,需要提供一種機制需要把所有的DTO和基礎組件在應用初始化的過程中加載到組件模型,在定義流程文件的時候不需要定義全路徑,而且通過註冊的bean映射到具體的實現組件,這樣的編排文件就變的更加簡單了。

流程解析

我們把節點分爲方法節點、bean節點、服務節點、條件節點、循環節點、子流程節點,我們來講一下主要的設計;

第一步:拿到流程ID,在定義的流程上下文獲取流程模型,如果獲取不到對應的流程,則拋出對應的異常;

第二步:處理主流程,處理主流程我們需要執行過程就行計時處理,通過解析請求參數和輸出參數,上下文並實例化成對象;加載所有的流程節點,並開始查到第一個定義的流程節點;

第三步:節點解析,根據定義的type類型,我們可以知道需要那種節點解析器去做處理;

第四步:節點處理,方法節點很簡單通過反射機制調用基礎組件;bean節點比方法節點多了一次bean到類的映射,也是通過反射執行組件;條件節點通過EL表達式進行匹配,可配置多個條件,既滿足if else場景,也需要滿足when case場景;服務節點需要我們自定義實現sdk定義一個輕量級框架,不依賴任務容器,需要在starter模塊實現等;

第五步:流程節點執行完成之後會獲取下一個節點,然後通過遞歸的形式調用,有多少節點就遞歸調用多少次,直到沒有下一個節點標識;

第六步:統計執行情況,包括耗時,響應參數;

第七步:異常處理機制,全局可自定義異常處理機制,當流程發生異常時回滾操作;

集成使用

我們參考Spring框架,低侵入松耦合設計思想。編排框架也應該滿足這個設計思想。因爲框架是需要集成到應用中使用的,我們希望框架儘可能低侵入,與業務代碼松耦合,替換、刪除起來也更容易些。我們基於Spring框架做集成,並提供starter依賴組件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章