來源:juejin.cn/post/7469330882945318922
作為一個優秀的程式設計師,要守住職業的底線。能簡單快速的完成的一件事,就一定要用簡單的方案快速完成。不可過度的設計,始終保持系統的簡潔!
曾幾何時,我對於流程編排這件事 嗤之以鼻,為什麼呢?我認為流程編排是典型地過度設計。
在我看來,程式碼越直觀越可靠,我不喜歡看程式碼的時候跳來跳去。但是流程編排後,要把各個方法放到擴充套件類,透過組合各個擴充套件類新建一個流程,實現業務功能,這能有什麼好處呢?
直到我來到一箇中臺團隊,才意識到流程編排能力是保命的能力。
業務中臺要接入很多的業務方,每個業務方並不是完全相同。很多時候無法完全複用,需要改造系統適應新的業務。
新增業務程式碼時,務必要保證原有業務不受影響,如果沒有流程編排能力,就會充斥大量的 if else 。
if (biz == BizA || biz == BizB) {//do some thing//這部分邏輯相同if (biz == BizA) {//差異化處理 }if(biz == BizB) {//差異化邏輯 }}
例如上面的程式碼,不同的業務線若有差異化邏輯,需要新增分支單獨處理。想象一下,當有 10 多個業務接入了你的系統,那麼一定讓人抓狂……
任何一個人都無法保證對 10 多種業務完全熟悉,每個人可能只負責 1 個業務,然而如果沒有程式碼邏輯的隔離,維護者只能在千絲萬縷中,才能找到目的碼邏輯。更可怕的是,每次新增一個業務,需要在原有的屎山中繼續
,不斷新增 if else。直到有一天,有一個倒黴蛋改錯了程式碼,導致其他重要業務受影響,引發線上故障。
想象一下,當你改了幾行程式碼以後,要求測試同學,迴歸10 多個業務線的全部邏輯?這顯然不現實。
以上的問題和痛點可歸納為:程式碼隔離性和業務擴充套件點問題。解決這兩類問題有如下手段!
-
使用流程引擎,為不同的業務配置不同的流程執行鏈 -
使用外掛擴充套件引擎,不同的業務實現差異化部分。
MemberClub 中大量使用流程引擎和外掛擴充套件引擎解決業務隔離性和擴充套件性 問題。
MemberClub是託管在Gitee平臺的開源專案,提供了付費會員的交易解決方案,在各類購買場景下提供各類會員形態的履約及售後結算能力,具體介紹可參見
https://gitee.com/juejinwuyang/memberclub
配置流程執行鏈
考慮到不同的會員產品交易提單流程不同,不同的產品應配置不同的流程,
DemoMemberPurchaseExtension
實現了購買擴充套件點,並且定義了三個流程執行鏈的配置方式。如截圖所示~
定義流程節點
流程節點中的方法包括
process
、success
、rollback
和 callback
方法。
流程執行
流程執行時 需提供流程上下文物件。呼叫
FlowChain.execute
方法即可
實際執行階段,各個流程節點被流程引擎串聯起來依次執行,類似於責任鏈的設計模式,具體執行順序如下圖所示。
依次執行每個流程節點的
process
方法,若 process
方法出現異常,則執行 rollback
方法。若所有的 process
方法執行成功,則倒序依次執行 success
方法。
流程引擎執行原理
以下是
FlowChain.execute
方法執行原理。public <T> voidexecute(FlowChain<T> chain, T context){ Exception exception = null;int index = -1;for (FlowNode<T> node : chain.getNodes()) {try { node.process(context); index++; } catch (Exception e) {if (e instanceof SkipException) { CommonLog.warn("當前流程:{} 發出 Skip請求,後續流程不再執行", node.getClass().getSimpleName());break; } exception = e;break; } }if (exception != null) {for (int i = index; i >= 0; i--) { FlowNode<T> node = chain.getNodes().get(i);try { node.rollback(context, exception); } catch (Exception e) { CommonLog.error("rollback執行異常,忽略 name:{}", node.getClass().getSimpleName(), e); } } } else {for (int i = index; i >= 0; i--) { FlowNode<T> node = chain.getNodes().get(i);try { node.success(context); } catch (Exception e) { CommonLog.error("success 執行異常,忽略 name:{}", node.getClass().getSimpleName(), e); } } }for (int i = index; i >= 0; i--) { FlowNode<T> node = chain.getNodes().get(i);try { node.callback(context, exception); } catch (Exception e) { CommonLog.error("callback執行異常,忽略 name:{}", node.getClass().getSimpleName(), e); } }if (exception != null) {throw exception; }}
以上全部程式碼地址,可以參見 MemberClub:
https://gitee.com/-/ide/project/juejinwuyang/memberclub/edit/master/-/memberclub.common/src/main/java/com/memberclub/common/flow/FlowChainService.java
MemberClub是託管在Gitee平臺的開源專案,提供了付費會員的交易解決方案,在各類購買場景下提供各類會員形態的履約及售後結算能力,一個非常好的專案,適合用來學習業務中臺系統,具體介紹可參見
Gitee開源地址:
https://gitee.com/juejinwuyang/memberclub
GitHub開源地址:
https://github.com/juejin-wuyang/memberclub
在這個專案中你可以學習到 SpringBoot 整合 以下框架或元件。
-
Mybatis-plus -
Sharding-sphere 多資料來源分庫分表 -
Redis/redisson -
Apollo -
Springcloud(feign/enreka) -
RabbitMQ -
H2 記憶體資料庫 -
Swagger -
Lombok+MapStruct
同時你也可以學習到以下元件的實現原理
-
流程引擎 -
擴充套件點引擎 -
分散式重試元件 -
通用日誌元件 -
商品庫存 -
分散式鎖元件 -
Redis Lua的使用 -
Spring 上下文工具類
官方站點:www.linuxprobe.com
Linux命令大全:www.linuxcool.com

劉遄老師QQ:5604215
Linux技術交流群:2636170
(新群,火熱加群中……)
想要學習Linux系統的讀者可以點選"閱讀原文"按鈕來了解書籍《Linux就該這麼學》,同時也非常適合專業的運維人員閱讀,成為輔助您工作的高價值工具書!