作者:李玉亮 JDEasyFlow是企業金融研發部自研的通用流程編排技術組件,適用於服務編排、工作流、審批流等場景,該組件已開源(https://github.com/JDEasyFlow/jd-easyflow),目前在部門的內部業務系統和科技輸出系統中廣泛應用,其他部門也有使用。 它的特點是簡單 ...
作者:李玉亮
JDEasyFlow是企業金融研發部自研的通用流程編排技術組件,適用於服務編排、工作流、審批流等場景,該組件已開源(https://github.com/JDEasyFlow/jd-easyflow),目前在部門的內部業務系統和科技輸出系統中廣泛應用,其他部門也有使用。
它的特點是簡單、靈活、易擴展,開發人員一般30分鐘可入門上手,半天可掌握其原理。它分為一個核心模塊和若幹擴展模塊,模塊之間松耦合,開發使用時可按需選擇、快速集成、漸進式應用,同時支持JSON內置規範和BPMN規範。它的實現原理也有其特色,後面有介紹。
支持的場景功能
節點流轉類型
支持順序流轉、條件流轉、迴圈流轉等。
節點功能類型
支持腳本節點、用戶節點和消息節點。
• 腳本節點:節點執行時運行一段代碼腳本
• 用戶節點:根據用戶的操作指令觸發節點執行
• 消息節點:接收消息後觸發節點執行
節點串並類型
支持串列執行、並行執行、串並組合執行等。
流程交互場景
支持單次交互一次執行多節點、多次交互一次執行一節點、多次交互一次執行多節點等。
子流程場景
JDEasyFlow支持子流程的場景,可將把複雜的流程節點拆分為子流程,便於業務邏輯抽象。
審批流程場景
JDEasyFlow提供了流程任務審批的能力;常用的審批、撤銷、駁回、會簽、加簽等功能都可支持;內置了簡單的動態表單。既支持從頁面發起和操作流程任務,也支持API的方式,京東OA審批系統也有對接。
功能架構
整體功能架構
JDEasyFlow的功能架構如下圖,功能模塊之間松耦合, 開發時可按需選擇、快速集成、漸進式應用。最簡單的使用方式為只在業務應用端引入jar包使用流程引擎。如果需要流程可視化功能,可集成BPMN規範模塊,如果還需要流程實例持久化、流程定義持久化等更豐富功能,則可以集成其他相關模塊。
流程引擎模塊
JDEasyFlow的核心模塊,此模塊提供了基於JSON格式的JDEasyFlow規範進行流程編排的能力,其他模塊均基於該模塊擴展,相當於流程執行的發動機、CPU。該功能模塊為獨立組件,無資料庫依賴,應用中引入jar包便可使用。
BPMN規範模塊
提供了基於BPMN規範進行流程定義和可視化的能力,流程可視化基於[bpmn-js](https://bpmn.io/),其本質為提供了將BPMN格式流程定義轉換為JDEasyFlow格式的能力。該模塊為獨立組件,僅依賴流程引擎模塊,無資料庫和服務依賴,應用中引入jar包便可使用。
目前可支持常用的BPMN元素:
• 任務:腳本任務、用戶任務、消息任務
• 事件:開始事件、結束事件、消息接收事件
• 網關:排他網關、並行網關、包容網關
流程定義和實例管理模塊
流程定義模塊支持流程定義的中心化、版本化管理,流程實例模塊支持流程實例的持久化和生命周期管理。該功能依賴資料庫,有服務端和ERP管理端。
任務/審批模塊
支持任務生成、任務分配等功能,常用的審批、撤銷、駁回、會簽、加簽等功能都可支持。該功能依賴資料庫,有服務端和ERP管理端。
系統架構
整體系統架構
JDEasyFlow的完整系統架構如下,主要有三個端:業務應用端、流程服務端、流程管理端,三個端可部署在單體應用中,也可分開部署。
中間件依賴
· 關係型資料庫(如Mysql)
· 緩存(如Redis或R2M)
· 服務通訊框架(如Java API調用或Http調用或JSF調用)
資料庫數據模型比較簡單清晰,見下圖:
性能說明
· 如果僅是服務編排場景,則流程的執行僅依賴記憶體和CPU,並且是在流程客戶端執行,性能上依賴於客戶端伺服器的性能,普通筆記本實測1秒可執行一個流程請求的1w+個節點,1秒可執行1萬+次含1個節點的流程請求
· 如果需要流程狀態管理和流程持久化功能,流程引擎在執行時會到流程服務端查詢和保存流程實例和流程節點的狀態,性能上主要依賴於資料庫的查詢和插入效率
· 對於流程任務審批功能,流程的任務審批流轉是在服務端執行,一方面取決於流程服務端的計算性能,另一方面同樣取決於資料庫的查詢和插入效率
可伸縮性說明
· 流程引擎屬於無狀態,可隨應用實例線性伸縮
· 流程服務端應用實例支持線性擴展
· 流程資料庫可通過分庫分表的方式支持大數據量的增長
實踐建議
在具體實踐中,建議部署統一的流程中心(見下圖),對流程定義統一管理。各系統的應用只需集成流程客戶端jar包進行流程節點開發和流程調用便可。如果系統只使用任務審批的功能,則只需要通過API和消息與流程中心交互便可。
使用示例
流程引擎使用示例
在源碼的test目錄下有quickstart測試用例(easyflow\easyflow-flow\src\test\java\com\jd\easyflow\flow\quickstart\QuickStartTest.java),可直接運行或調試以瞭解使用方式和運行原理。具體實踐步驟如下:
1、代碼中引入easyflow-flow jar包,以maven為例:
<dependency>
<groupId>com.jd.easyflow</groupId>
<artifactId>easyflow-flow</artifactId>
<version>{替換為最新版本}</version>
</dependency>
2、編寫流程定義文件,以node001->node002→node003的執行順序為例:
{"id": "quickstart_001", "name": "Quick Start 001",
"nodes": [
{"id": "node001","name": "Node001","action": {"createExp": "new com.jd.easyflow.flow.quickstart.QuickStart001Node01Action()"},"start": true,"post": {"to": "node002"}},
{"id": "node002","name": "Node002","action": {"createExp": "new com.jd.easyflow.flow.quickstart.QuickStart002Node01Action()"},"post": {"to": "node003"}},
{"id": "node003","name": "Node003","action": {"createExp": "new com.jd.easyflow.flow.quickstart.QuickStart003Node01Action()"}}
]
}
其中QuickStart001Node01Action等為java節點動作類。完整的流程定義配置項可見: https://github.com/JDEasyFlow/jd-easyflow/wiki/Flow-engine-usage (公網)
3、編寫應用啟動時載入流程引擎的代碼
FlowEngineImpl flowEngine = new FlowEngineImpl();
flowEngine.setFlowPath("classpath:flow/quickstart/quickstart_001.json");
flowEngine.init();
Spring環境可直接定義FlowEngineImpl bean.
4、編寫具體流程調用執行的代碼
FlowParam param = new FlowParam("quickstart_001");
FlowResult result = flowEngine.execute(param);
完整測試用例的執行結果列印如下:
[main ] INFO FlowEngineImpl - Start parsing definition files:easyflow-flow/target/test-classes/flow/quickstart/quickstart_001.json
[main ] INFO FlowEngineImpl - SART EXECUTE FLOW, flowId:quickstart_001 nodeIds:null
[main ] INFO BaseFlowRunner - EXECUTE NODE:node001
[main ] INFO QuickStart001Node01Action - Execute Node 001
[main ] INFO BaseFlowRunner - NEXT NODES:node002
[main ] INFO BaseFlowRunner - EXECUTE NODE:node002
[main ] INFO QuickStart002Node01Action - Execute Node 002
[main ] INFO BaseFlowRunner - NEXT NODES:node003
[main ] INFO BaseFlowRunner - EXECUTE NODE:node003
[main ] INFO QuickStart003Node01Action - Execute Node 003
[main ] INFO BaseFlowRunner - NEXT NODES:
[main ] INFO QuickStartTest - Execute finish, current node is:node003
BPMN模塊使用示例
打開easyflow-flow-bpmn/BPMNDesigner.html流程設計器. 點擊導入按鈕,導入easyflow-flow-bpmn/src/test/resources/flow/quickstart/quickstart_001.bpmn文件,可在設計器中看到和以上JSON定義等價的BPMN流程定義.
代碼集成使用時只需要將FlowEngineImpl的flowParser設置為BpmnFlowParser.
更多
以上只是流程引擎和BPMN模塊的簡單使用示例,JDEasyFlow還包含其他模塊、可支持很多的配置項和使用場景,更多使用可見最後的對接使用介紹.
實現原理
目前市面上的流程編排組件基本都是基於圖(邊和頂點)結構的,而本組件是參考了電腦指令執行模型而實現,借鑒了程式計數器的實現原理,引擎內部通過類似程式計數器(PC)的待執行節點棧來維護後繼節點;可以理解為是一種高級業務編程語言,它同時也是圖靈完備的。
流程引擎核心模型名詞只有一個:節點(Node),節點的功能為執行邏輯並輸出後續節點 。
開發態可定義有限的節點,通過每個節點與其後續節點連接形成有向圖;運行態按規則邏輯進行節點流轉,支持並行執行,支持順序、條件或迴圈,支持fork-join。
概念:
• 流程:一個業務流程的抽象
• 節點:流程的組成單位,一個節點能夠執行節點動作同時可返回後繼節點
節點內部構件:
節點內部構件的組成是可自定義的,流程引擎提供了預設實現,其內部構件包括了前處理器(PreHandler)、節點動作(NodeAction)、後處理器(PostHandler)
• 前處理器:判斷該節點是否可以執行動作
• 節點動作:真實的業務功能處理
• 後處理器:負責計算後續節點
流程引擎執行邏輯
流程引擎有一個或多個流程觸發節點,流程觸發後執行如下邏輯:
1. 初始化流程上下文
2. 得到流程起始節點ID,放入執行棧
3. 如果執行棧為空,則返回,否則執行當前節點
-
預檢查
-
執行Action
-
計算後繼節點ID並返回
4. 將後繼節點放入執行棧,從棧中取出待執行節點,跳到第3步
因此JDEasyFlow整體的特色為簡單:
• 模型簡單:核心模型概念就是節點的流轉
• 擴展簡單:提供了監聽器、過濾器功能,方便橫向切麵;節點支持自定義實現
• 定義簡單:只需要通過JSON進行節點流轉邏輯配置便可,也支持BPMN格式
• 運行簡單:代碼調用流程引擎,傳入流程ID和業務參數便可
• 使用簡單:引入組件包便可使用,比較輕量
適用場景和對接使用說明
適用場景
理論上JDEasyFlow可滿足任何流程場景,它主要可解決三類問題:
• 流程可編排:將業務流程抽象為軟體流程,保證軟體是現實的真實反映;不同場景可定義不同流程,且流程易修改
• 功能松耦合:將業務節點抽象為軟體流程節點,一方面實現功能的松耦合,另一方面實現節點的可復用
• 流程可視化:所見即所得,方便業務產品人員和軟體研發人員基於同一語言的交流,也便於流程監控
在實際軟體系統開發過程中,如果有如下訴求,可考慮使用流程編排:
• 業務流程是有明顯的多個節點組成
• 希望流程可靈活變更
• 業務流程級別比程式流程高一層,在編程語言級別難以聚合和治理(如一個流程即需要前臺操作,又有外系統參與,又有後臺操作,在實現上入口分散)
對接使用
JDEasyFlow的所有文檔可見: https://github.com/JDEasyFlow/jd-easyflow/wiki (公網)
歡迎大家對接使用,有相關使用問題可聯繫: [email protected]