Spring Boot + liteflow 規(guī)則引擎,太香了!
在日常的開發(fā)過程中,經(jīng)常會遇到一些串行或者并行的業(yè)務流程問題,而業(yè)務之間不必存在相關性。
在這樣的場景下,使用策略和模板模式的結(jié)合可以很好的解決這個問題,但是使用編碼的方式會使得文件太多,在業(yè)務的部分環(huán)節(jié)可以這樣操作,在項目角度就無法一眼洞穿其中的環(huán)節(jié)和邏輯。
在本文中,將引入規(guī)則引擎從全局角度來解決這個問題,這就是今天要介紹的主角 liteflow。
1. liteflow 規(guī)則引擎
liteflow 是一個輕巧而且強大的規(guī)則引擎,能夠?qū)崿F(xiàn)開箱即用,可以在短時間內(nèi)就可以完成復雜的規(guī)則編排,下圖是 liteflow 的整體架構。liteflow 支持較多的規(guī)則文件格式,比如 xml/json/yaml, 對于規(guī)則文件的存儲方式可以有sql/zk/nacos/apollo 等。
圖片
liteflow 的使用是從獲取上下文開始的,通過數(shù)據(jù)上下文來解析對應的規(guī)則文件,通過 liteflow 執(zhí)行器來執(zhí)行對應的鏈路,每個鏈路上都有需要執(zhí)行的業(yè)務 node(即節(jié)點組件,可以支持多種語言腳本, groovy/js/python/lua等), 各個業(yè)務node 之間是獨立的。liteflow 對應的官方網(wǎng)址和依賴如下所示:
liteflow 規(guī)則引擎官方網(wǎng)址
- https://liteflow.yomahub.com
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.10.6</version>
</dependency>liteflow 可以支持如下所示的復雜流程
圖片
此外,liteflow 可以支持熱部署,可以實時替換或者增加節(jié)點,即修改規(guī)則文件后可以實時生效。
圖片
2. liteflow 的使用方法
2.1 組件
liteflow 的組件在規(guī)則文件中即對應的節(jié)點,組件對應的種類有很多,具體的如下所示:
- 普通組件
普通組件需要集成的是 NodeComponent, 可以用在 when 和 then 邏輯中,具體的業(yè)務需要在 process 中去執(zhí)行。同時在 node 節(jié)點中,可以覆蓋 iaAccess 方法,表示是否進入該節(jié)點執(zhí)行業(yè)務邏輯,isContinueOnError 判斷在出錯的情況下是否繼續(xù)執(zhí)行下一個組件,默認為 false。isEnd 方法表示是否終止流程,默認為true。
- 選擇組件
選擇組件是通過業(yè)務邏輯來判斷接下來的動作要執(zhí)行哪一個節(jié)點,類似于 Java中的 switch , 在代碼中則需要繼承 NodeSwitchComponent 實現(xiàn) processWitch 方法來處理業(yè)務。
# flow 規(guī)則表達式 選擇組件
SWITCH(a).to(b, c);
# processWitch 表達式需要返回的是 b 或者 c 字符串來執(zhí)行相應的業(yè)務邏輯
# flow 規(guī)則表達式 條件組件
IF(x, a, b);- 條件組件
條件組件稱之為 if 組件,返回的結(jié)果是 true 或者 false, 代碼需要集成 NodeIfComponent 重寫 processIf 方法,返回對應的業(yè)務節(jié)點,這個和選擇組件類似。
在官方文檔中,還有次數(shù)循環(huán)組件,條件循環(huán)組件,循環(huán)迭代組件,和退出循環(huán)組件,作者認為其應用場景比較復雜,可以使用簡單的普通組件來替代,畢竟是輕量級的規(guī)則引擎,主要作用就是為了編排流程順序,復雜的場景就升級使用工作流了,所以這里只介紹以上三種組件。
2.2 EL 規(guī)則文件
規(guī)則文件的編寫和組件的使用是對應的,這里使用xml 的形式來編寫。
# 文件編排, then 代表串行執(zhí)行 when 表示并行執(zhí)行
# 串行編排示例
THEN(a, b, c, d);
# 并行編排示例
WHEN(a, b, c);
# 串行和并行嵌套結(jié)合
THEN( a, WHEN(b, c, d), e);
# 選擇編排示例
SWITCH(a).to(b, c, d);
# 條件編排示例
THEN(IF(x, a),b );2.3 數(shù)據(jù)上下文
在 liteflow 中,數(shù)據(jù)上下文的概念非常重要,上下文對象起到參數(shù)傳遞的作用,因為不同業(yè)務需要的輸入輸出參數(shù)是不同的,所以上下文非常的重要。
# 執(zhí)行流程時,需要傳遞el文件,初始化參數(shù)以及上下文對象,這里的上下文可以設置多個
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始參數(shù), CustomContext.class);因為上下文傳入的是一個 class 類型參數(shù),流程參數(shù)是可以傳入?yún)?shù)的,一般情況下是在第一個節(jié)點中,將傳入?yún)?shù)設置到上下文對象中。
2.4 參數(shù)配置
在 liteflow 中,需要配置的內(nèi)容有規(guī)則文件地址,節(jié)點重試(執(zhí)行報錯時可以進行重試,類似于 spring-retry), 流程并行執(zhí)行線程池參數(shù)配置,流程的請求ID配置。
liteflow:
# 規(guī)則文件 失敗重試次數(shù) 打印執(zhí)行日志 監(jiān)控日志
ruleSource :liteflow/*.el.xml
retry-count:0
print-execution-log:true
monitor:
enable-log:true
period:300000
request-id-generator-class:com.platform.orderserver.config.AppRequestIdGenerator
# 上下文的最大數(shù)量槽
slot-size :10240
# 線程數(shù),默認為64
main-executor-works:64
# 異步線程最長等待時間 秒
when-max-wait-seconds:15
# when 節(jié)點全局異步線程池最大線程數(shù)
when-max-workers:16
# when 節(jié)點全局異步線程池隊列數(shù)
when-queue-limit:5120
# 在啟動的時候就解析規(guī)則
parse-on-start:true
enable:true3. 業(yè)務實踐
之前介紹了 liteflow 的一些概念,在這里結(jié)合一些業(yè)務場景來進行演示:
主要使用電商場景的應用,訂單完成后,進行積分的發(fā)放,消息發(fā)送,同時并行發(fā)送短信和郵件。
<?xml versinotallow="1.0" encoding="UTF-8"?>
<flow>
<chain name="test_flow">
THEN(
prepareTrade, grantScore, sendMq, WHEN(sendEmail, sendPhone)
);
</chain>
</flow>在訂單完成之后異步執(zhí)行,傳遞參數(shù)并執(zhí)行相應的規(guī)則流程。
圖片
在正式處理業(yè)務流程之前,需要先進行數(shù)據(jù)的預處理,將流程入?yún)⑥D(zhuǎn)轉(zhuǎn)換成上下文對象,方便參數(shù)的傳遞和設置。
圖片
在具體的業(yè)務處理環(huán)節(jié),以積分發(fā)放為例,可以獲取上下文對象進行業(yè)務操作,同時也可以重寫 isAccess 方法,來判斷是否處理該節(jié)點。
圖片
如上圖所示,具體的業(yè)務流程都可以抽象成一個 node 節(jié)點,存放在 test_flow.el.xml 中進行執(zhí)行,其它的代碼都和積分發(fā)放類似,這里就不再贅述,可以參見代碼。
4. 總結(jié)
liteflow 中的絕大部分是在啟動時完成的,包括規(guī)則解析、注冊組件以及組裝信息,其執(zhí)行性能很高,同時也可以打印每個業(yè)務環(huán)節(jié)的耗時以及統(tǒng)計信息。




































