構建企業數字化轉型之某大廠審批流引擎核心技術揭秘


1. 定義

企業數字化轉型的道路上,必不可少的一項就是審批流程的線上化,都需要搭建自己的審批系統,而審批系統的核心就是審批流引擎

什么是審批流引擎呢?

是一個工具包,用來驅動審批類業務的執行,通過使用這個引擎,可以方便快速的實現各類審批相關的功能,如:審批、同意、或簽、並簽、串簽、拒絕、駁回、回退到任意節點、前加簽、后加簽、平行加簽、平行減簽、外部調用節點、抄送、填寫、主子流程、分支、選擇、流程預測、流程仿真、取回、撤銷、傳閱、以及各種加減簽與或並簽的任意嵌套。

2. 現有技術

業內的現有技術一般分為三大派系,一個是直接使用開源的工作流引擎作為審批流引擎,一個是在開源的工作流引擎的基礎之上進行的二次開發,最后一個是完全的自研

2.1 開源的工作流引擎

這種技術的一個基本的邏輯就是把工作流引擎當做審批流引擎來使用,常見的就是activiti,也有flowable、camunda,但由於它們二者都是直接或間接來自於actitivi,雖然做了一些改進,但區別不是很大。

以activti為例,一個典型的技術架構如下圖所示:

流程圖片

實踐中,使用BPMN2.0協議作為審批流流程定義的載體,使用activiti工作流引擎解析並執行這個流程,引擎通過回調的方式來執行自定義的審批業務,審批業務通過API的方式來調用引擎,如此循環,直到結束。需要注意的是,Client可以調用其中的任何一層

這種技術優缺點如下

優點:

  • 開源的多年成熟技術
  • 文檔資料比較多

缺點:

  • 對絕大部分審批業務沒有直接的API或回調支持,需要自己開發
  • 一些復雜的場景,如:或並簽與加減簽的無限嵌套,支持的力度非常的弱,有時需要繞過工作流引擎,而去直接修改數據庫本身,這樣帶來的危害是比較大的
  • 開源的代碼量巨大,50W行左右,遇到一些棘手的問題,又找不到資料,必需看源碼找問題的時候,會非常非常的痛苦,對開發不友好,學習成本高
  • 與BPMN協議依賴性較強,因審批流協議與BPMN協議的交集較小,需要BPMN協議的擴展功能來表達審批流語義,導致語義含糊,表達力不強

從根本上來說,直接把工作流引擎當做審批流引擎是混淆了工作流與審批流的概念,把一些審批流的邏輯范疇強行加到工作流上,把個性當共性,最終導致了復雜性的爆炸,審批業務做的不倫不類,無法做大做強。

2.2 二次開發

這種技術是在開源的工作流引擎的基礎之上進行的二次開發,把activiti之流當做底層的技術底座,進行了一些封裝,一般的技術架構如下圖所示:

流程圖片

使用的時候,Client直接調用審批流API接口,然后進行相應的邏輯處理,最后調用工作流引擎,完成整個流程

這種技術優缺點如下

優點:

  • 屏蔽了底層技術細節,接口對使用者友好
  • 對大部分審批業務提供了直接的支持

缺點:

  • 因其技術底座使用了activiti之流,故其帶來的困擾一點沒有減少,直接對引擎的維護者不友好,間接提高BUG率,進而影響上層業務,不穩定性增大
  • 對一些特定的RDBMS的支持較差,如:達夢國產數據庫、自研的內存數據庫,需要做大量的二次開發,修改底層源代碼
  • 對數據庫的異構性支持幾乎沒有,會直接影響本地事務的一致性

2.3 自研

每一家的解決方案各自不同,使用的技術底座不同,協議不同,持久化機制不同,接口參數不同,但一個相同的邏輯就是有針對性的對審批業務提供了直接的支持,不在混淆工作流與審批流的概念,對開發更加的友好,開發更加的簡單,同時對現有的審批業務的范疇之內,提供了一些擴展能力,雖然有上述優點,缺點也不容易忽視,如下:

  • 如果審批業務有了進化,提出了一些新的概念,而擴展性又覆蓋不到的話,那么就需要開發引擎本身來進行支持,這對於軟件的分發、升級、部署、數據一致性方面提出了挑戰
  • 與某一持久化機制強綁定,無論是RDBMS、KV還是文件,顯得很笨重,集成的時候,會引起與現有基礎設施不一致的問題,很是麻煩

3. 我們的技術

我們采用的是自研的方式,走了一條很不一樣的技術路線,完全自研了工作流引擎框架,在這基礎之上,構建了自己的審批流引擎,具有如下的特點:

  • 與審批業務強耦合,開箱即用
  • 使用簡單,貧血模型,無狀態依賴
  • 本身代碼量少,1W行左右,易於維護
  • 只是一個jar包,可嵌入到任何業務系統中
  • 不依賴具體的數據庫,無論關系型的還是非關系型的,對持久化提供了擴展
  • 不依賴某一個流程協議,如:BPMN,而是使用類似流程虛擬機的形式,對審批流定義本身提供了支持
  • 可擴展自己業務特定的流程節點
  • 可擴展自己業務特定的執行人指定邏輯
  • 可擴展自己業務特定的流程流轉事件
  • 依賴少,只依賴slf4j、kryo等必要組件,不依賴任何工作流引擎,如:activiti、flowable等
  • 可以方便的集成進Spring MVC,Spring Boot等
  • 可以方便的控制本地事務、事務集成等
  • 可運行時確定具體審批人,而不是在定義期
  • 擴展性合適,既不是什么都可以擴展,也不是什么都不可以擴展,即:只擴展那些與審批相關的點

下面詳細闡述我們是怎么實現的......

3.1 理論基礎

工作流引擎的兩大模塊,一個是流程定義,一個是流程執行

現有的流程定義都是使用BPMN協議進行描述,這個協議實在是太龐大了,本着第一性原理,我們對工作流引擎的本質進行了深入的挖掘,重新對工作流進行了定義,提出了元模式的概念。

具體來講,詳細研究了43種工作流控制模式,這些工作流控制模式的組合基本上就能覆蓋住絕絕絕大多數工作流場景,一般來講,對43種直接進行支持就可以了,但43種未免也有些過多,加上以后也會出現有44、45、46種模式,所以我們更進一步的對這43種進行泛化與抽象,最終得出了6種工作流控制元模式,通過這6種元模式的組合與API調用,就能夠直接或間接支持43種控制模式,同時,對未來出現的模式也有一定的支持,這6種為:

  • 事件:事用來表示發送一個事件,也可以表示等待接收一個事件,事件是廣播的方式傳播的
  • 活動:泛指各類活動任務,如:人工任務、腳本任務、服務任務、用戶任務、審批節點任務等,是與各個業務相關聯的
  • 子流程:也是一個流程,用來重用或消除重復、或者減少主流程的復雜性
  • 分裂:所有需要並行做的事情,都要用此元素,這里並不規定分裂邏輯,以及分裂后的分支的數目
  • 匯聚:同步並行分支,在此之后,多條分支合並為一條,這里也並不規定同步邏輯,以及多次同步的方法
  • 流轉:以上五種元素的流轉方向,一個源,一個目標,流程從源流轉到目標

如下圖所示:

流程圖片

對於流程執行來講,業內一般采用以下兩種技術:

  • 基於FSM的技術:由於FSM天生的缺陷,對於狀態的擴展能力較弱,應用面較窄,只能在特定業務領域有較好的落地應用
  • 基於Token的技術:市面上最主流的技術,優點是理論模型較健全,缺點是落地較復雜,實現繁瑣,理解起來較困難

我們使用的並不是二者之一,而是基於無限狀態機模型的一種技術實現,如下圖:

流程圖片

這種技術的本質是個循環,其設計靈感來自於CPU的執行邏輯,不斷的讀取狀態,接下來對狀態進行處理,處理的結果也是一個狀態,然后繼續,直到沒有狀態或狀態暫時無法處理,這里面還有個類似與中斷的喚醒狀態的邏輯,鑒於保密原則,此處不在展開

有了這些理論基礎,接下來就是落地實現了

3.2 工作流引擎框架

在落地實現的過程中,我們發現各種垂直業務領域的工作流都有着一些共性,同時也有着一些個性,而且,這些共性是框架維度的,並不是庫維度的,因此,我們對此進行了抽象,提出了工作流引擎框架的概念。具體來講,它是工作流引擎的模板,通過使用這個框架,可以快速的開發實現各種業務域的“工作流”引擎,包括審批領域的審批流引擎、任務領域的任務流引擎、采購領域的采購流引擎等,它提供了基本的流程定義與流程執行能力,及其強大的擴展能力

有別於傳統的工作流引擎,它們對特定業務領域(如:審批流、任務流)的直接支持實在是太弱了,根本原因在於它們太通用了,通用到了為了支持各種工作流場景,把一塊木板變成了木削,以至於當我要制造一個櫃子的時候,需要從木削開始加工,這極大的增加了工作量,在加上學習成本,可以說,這不是在提高效率,而是在降低效率。所以,一般來講,通用性越強,適用性越低,反之亦然。

具體到實現層面,框架一共分為兩層

第一層為ISM,也就是無限狀態機,是個微內核,其概念模型如下圖所示

流程圖片

Func是一個狀態轉換器,其有兩個方法,一個是transfer(),用來消費一個State,然后,生產一個State,另一個是eventHandle,用來消費一個消息,然后生產一個State;Funs維護着Func;Case是一個實例,其內部維護着所有的狀態(State),記錄着狀態變化的歷史,每一個狀態包含:

  • id:唯一標識本狀態
  • tobeStarted:需要對本狀態進行處理的Func集合
  • ing:進行中的Func集合
  • toIngMsg:給進行中的Func發的消息
  • alreadySend:已經處理完消息的Func集合

第二層為PVM,也就是流程虛擬機,通過這個虛擬機可以進行流程定義、流程執行、與中斷喚醒等操作,如下圖所示

流程圖片

流程定義(Definition)繼承了Funcs,從而有了管理Func的能力,流程中的節點(Node)繼承了Func,從而有了消費與產出State的基本能力;由Transition來表示兩個節點之間的流轉,指定了來源節點與目標節點;流程實例(Instance),使用了流程定義,從而可以據此來發起一個流程,同時,也使用了Case,進行流程實例的流轉;對於節點來說,具象化了工作流領域內的常用的一些節點及其對狀態的處理邏輯,包括:

  • 活動節點Activity,以及以此為基礎的子流程節點SubProcess
  • 並發分裂網關Fork,以及與其配套使用的同步匯聚網關Join
  • 事件節點Event,以及其兩個重用分類,發送事件節點TxEvent,及其派生類EndEvent,接收事件節點RxEvent,及其派生類StartEvent

有了這個框架之后,就具備了基本的工作流流程定義與執行能力,能夠通過此來開發上層的審批領域的審批流引擎了

3.3 審批流引擎

審批流引擎設計到的點非常多,由於篇幅所限,這里只分享最重要幾點

第一個是在審批流流程定義層面,我們繼承了Activity節點,派生出了審批節點、抄送節點、填寫節點等

第二個是在API層面,我們直接提供了審批、同意、或簽、並簽、串簽、拒絕、駁回、回退到任意節點、前加簽、后加簽、平行加簽、平行減簽、外部調用節點、抄送、填寫、主子流程、分支、選擇、流程預測、流程仿真、取回、撤銷、傳閱等方法,可以直接調用

第三個是在流程執行層面,整個流程是個PVM,每個審批節點內部也有個PVM,這么做的目的是因為審批業務的復雜性,同時也是一種現有能力的復用,由於PVM的足夠輕量,使得這種模式成為了可能,如下圖所示:

流程圖片

第四個是在流轉層面,每一次流轉的前后變化都存儲在一個上下文中,通過對比前后變化,就能夠得到一些信息,包括:

  • 哪些節點已經開始執行了
  • 哪些節點已經完成了,包括取消
  • 哪些任務生成了
  • 哪些任務完成了,包括取消

從而,可以據此信息來進行下一步的處理,如:持久化、回退等

第五個是通過訪問者模式,提供了對流程定義合法性的發起前的檢查能力,同時提供了一些默認實現,也可自行擴展

第六個是直接提供了流程預測的方法,該方法實現的內在邏輯為:在內存中模擬整個流程的流轉,把其中涉及到的一些預測信息存儲在一個Map中,這種方法有別於傳統的使用數據庫的方式,即快又不污染數據庫中的數據,同時也可並行執行,在預測過程中,不會阻塞正常流程的流轉

第七個是在節點擴展性方面,可以通過派生自審批節點的方式自行擴展自己特定審批邏輯的審批節點,也可通過派生自Activity、甚至是Func的方式,來擴展特定功能的節點

第八個是在分支條件表達式方面,對具體的表達式語法、語言進行了解耦,由其具體的表達式解析類進行表達式的解析,只要把Bool結果告知引擎即可

第九個是對流程實例變量的弱化,弱化為一個Map,這樣可以表達更多的信息

4. 未來展望

  • 在完善審批流引擎本身能力的同時,提供豐富的文檔與示例,方便大家使用
  • 基於審批流引擎,研發下一代審批流系統+,提供完善的集成能力,同時提供一些通用工作流能力
  • 建設審批流前端頁面組件能力,方便流程定義等前端復雜功能的實現


免責聲明!

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



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