SpringBoot?LiteFlow引擎框架使用原理解析
一、LiteFlow 簡介
LiteFlow
是一個輕量且強(qiáng)大的國產(chǎn)規(guī)則引擎框架,可用于復(fù)雜的組件化業(yè)務(wù)的編排領(lǐng)域。幫助系統(tǒng)變得更加絲滑且靈活。利用LiteFlow
,你可以將瀑布流式的代碼,轉(zhuǎn)變成以組件為核心概念的代碼結(jié)構(gòu),這種結(jié)構(gòu)的好處是可以任意編排,組件與組件之間是解耦的,組件可以用腳本來定義,組件之間的流轉(zhuǎn)全靠規(guī)則來驅(qū)動。LiteFlow
擁有開源規(guī)則引擎最為簡單的DSL
語法。 LiteFlow官網(wǎng)
LiteFlow
于2020
年正式開源,2021
年獲得開源中國年度最受歡迎開源軟件殊榮。于2022
年獲得Gitee
最有價值開源項目GVP
榮譽(yù)。是一個正處在高速發(fā)展中的開源項目。LiteFlow
是一個由社區(qū)驅(qū)動的項目,擁有一個2500
多人的使用者社區(qū)。雖然相比Acitiviti
、Flowable
來說,LiteFlow
的知名度要低得多,功能也沒有這些知名成熟引擎那么強(qiáng)大,但LiteFlow
還是有諸多優(yōu)點,能夠滿足你絕大部分的場景。這些優(yōu)點包括:
【1】規(guī)則多樣化: 規(guī)則支持xml
、json
、yml
三種規(guī)則文件寫法方式。
【2】使用便捷: 引幾個jar
包、實現(xiàn)幾個接口、寫一個流程編排文件,就能運行。
【3】編排豐富: 支持串行、并行、選擇、循環(huán)、異常處理、嵌套等各種編排方式。
【4】事件監(jiān)聽: 支持事件觸發(fā)和狀態(tài)變化監(jiān)聽,可以方便地擴(kuò)展和定制工作流處理邏輯。
【5】異步超時: 支持異步執(zhí)行和超時控制,可以提高系統(tǒng)的并發(fā)處理能力和穩(wěn)定性。
【6】支持腳本: 支持各種主流腳本語言。
【7】配置源豐富: 支持將流程定義放到ZK/DB/Etcd/Nacos/Redis/Apollo
和自定義擴(kuò)展等。相當(dāng)于可以實現(xiàn)動態(tài)配置更改。
【8】定制化: 高度可定制化,用戶可以根據(jù)自己的需求自由擴(kuò)展和定制LiteFlow
的各種組件和功能。
【9】支持眾多腳本語言: LiteFlow
的腳本組件,支持眾多腳本語言Groovy/JavaScript/QLExpress/Python/Lua/Aviator/Java
,完全和Java
打通,你可以用腳本來實現(xiàn)任何邏輯。
【10】優(yōu)雅熱刷新機(jī)制: 規(guī)則變化,無需重啟您的應(yīng)用,即時改變應(yīng)用的規(guī)則。高并發(fā)下不會因為刷新規(guī)則導(dǎo)致正在執(zhí)行的規(guī)則有任何錯亂。
【11】支持廣泛: 不管你的項目是不是基于Springboot
,Spring
還是任何其他java
框架構(gòu)建,LiteFlow
都能游刃有余。
【12】上下文隔離機(jī)制: 可靠的上下文隔離機(jī)制,你無需擔(dān)心高并發(fā)情況下的數(shù)據(jù)串流。
【13】性能卓越: 框架本身幾乎不消耗額外性能,性能取決你的組件執(zhí)行效率。
【14】自帶簡單監(jiān)控: 框架內(nèi)自帶一個命令行的監(jiān)控,能夠知道每個組件的運行耗時排行。
適合使用的這項技術(shù)的系統(tǒng)
在每個公司的系統(tǒng)中,總有一些擁有復(fù)雜業(yè)務(wù)邏輯的系統(tǒng),這些系統(tǒng)承載著核心業(yè)務(wù)邏輯,幾乎每個需求都和這些核心業(yè)務(wù)有關(guān),這些核心業(yè)務(wù)業(yè)務(wù)邏輯冗長,涉及內(nèi)部邏輯運算,緩存操作,持久化操作,外部資源調(diào)取,內(nèi)部其他系統(tǒng)RPC
調(diào)用等等。時間一長,項目幾經(jīng)易手,維護(hù)成本就會越來越高。各種硬代碼判斷,分支條件越來越多。代碼的抽象,復(fù)用率也越來越低,各個模塊之間的耦合度很高。一小段邏輯的變動,會影響到其他模塊,需要進(jìn)行完整回歸測試來驗證。如要靈活改變業(yè)務(wù)流程的順序,則要進(jìn)行代碼大改動進(jìn)行抽象,重新寫方法。實時熱變更業(yè)務(wù)流程,幾乎很難實現(xiàn)。
如何打破僵局?LiteFlow
為解耦邏輯而生,為編排而生,在使用LiteFlow
之后,你會發(fā)現(xiàn)打造一個低耦合,靈活的系統(tǒng)會變得易如反掌!
二、LiteFlow 原理
如果你要對復(fù)雜業(yè)務(wù)邏輯進(jìn)行新寫或者重構(gòu),用LiteFlow
最合適不過。它是一個編排式的規(guī)則引擎框架,組件編排,幫助解耦業(yè)務(wù)代碼,讓每一個業(yè)務(wù)片段都是一個組件。
LiteFlow
的核心是“流程即代碼”,即將業(yè)務(wù)流程和代碼結(jié)構(gòu)緊密耦合在一起。LiteFlow
采用基于XML
文件的流程定義方式,通過定義流程節(jié)點和連線來描述整個工作流程。每個流程節(jié)點都對應(yīng)著Java
代碼中的一個方法,而連線則對應(yīng)著方法之間的調(diào)用關(guān)系。這樣一來,我們就可以非常直觀地看到整個業(yè)務(wù)流程的處理過程,而且在修改流程時也更加方便快捷。
組件可實時熱更替,也可以給編排好的邏輯流里實時增加一個組件,從而改變你的業(yè)務(wù)邏輯。
編排語法強(qiáng)大到可以編排出任何你想要的邏輯流程例如:
三、使用場景
LiteFlow
適用于哪些場景: LiteFlow
適用于擁有復(fù)雜邏輯的業(yè)務(wù),比如說價格引擎,下單流程等,這些業(yè)務(wù)往往都擁有很多步驟,這些步驟完全可以按照業(yè)務(wù)粒度拆分成一個個獨立的組件,進(jìn)行裝配復(fù)用變更。使用LiteFlow
,你會得到一個靈活度高,擴(kuò)展性很強(qiáng)的系統(tǒng)。因為組件之間相互獨立,也可以避免改一處而動全身的這樣的風(fēng)險。
LiteFlow
不適用于哪些場景: LiteFlow
不適合角色任務(wù)之間的流轉(zhuǎn),類似于審批流,A審批完應(yīng)該是B審批,然后再流轉(zhuǎn)到C角色。這里申明下,LiteFlow
只做基于邏輯的流轉(zhuǎn),而不做基于角色任務(wù)的流轉(zhuǎn)。如果你想做基于角色任務(wù)的流轉(zhuǎn),推薦使用flowable
,activiti
這2個框架。
四、JDK支持情況
LiteFlow
要求的最低的JDK
版本為8
,支持JDK8~JDK17
所有的版本。如果你使用JDK11
以上,確保LiteFlow
的版本為v2.10.6
及其以上版本。因為LiteFlow
從v2.10.6
開始,對JDK11
和JDK17
進(jìn)行了詳細(xì)的用例測試,通過了全部的900
多個測試用例。而在v2.10.6
以下版本,在JDK11
以上是未經(jīng)過測試用例保障的。特別需要注意的是,如果你使用JDK11
及其以上的版本,請確保jvm
參數(shù)加上以下參數(shù):
--add-opens java.base/sun.reflect.annotation=ALL-UNNAMED
五、Springboot 整合流程
LiteFlow
要求的Springboot
的最低的版本是2.0
。支持的范圍是Springboot 2.X ~ Springboot 3.X
。如果你使用了最新的Springboot 3.X
,相應(yīng)的JDK版本也要切換為JDK17
。
LiteFlow
提供了liteflow-spring-boot-starter
依賴包,提供自動裝配功能
<dependency> <groupId>com.yomahub</groupId> <artifactId>liteflow-spring-boot-starter</artifactId> <version>2.11.3</version> </dependency>
組件定義
在依賴了以上jar
包后,你需要定義并實現(xiàn)一些組件,確保SpringBoot
會掃描到這些組件并注冊進(jìn)上下文。
@Component("a") public class ACmp extends NodeComponent { @Override public void process() { //do your business } }
以此類推再分別定義b,c組件:
@Component("b") public class BCmp extends NodeComponent { @Override public void process() { //do your business } } @Component("c") public class CCmp extends NodeComponent { @Override public void process() { //do your business } }
SpringBoot配置文件
然后,在你的SpringBoot
的application.properties
或者application.yml
里添加配置(這里以yaml
為例,properties
也是一樣的)
liteflow: #規(guī)則文件路徑 rule-source: config/flow.el.xml #-----------------以下非必須----------------- #liteflow是否開啟,默認(rèn)為true enable: true #liteflow的banner打印是否開啟,默認(rèn)為true print-banner: true #zkNode的節(jié)點,只有使用zk作為配置源的時候才起作用,默認(rèn)為/lite-flow/flow zk-node: /lite-flow/flow #上下文的最大數(shù)量槽,默認(rèn)值為1024 slot-size: 1024 #FlowExecutor的execute2Future的線程數(shù),默認(rèn)為64 main-executor-works: 64 #FlowExecutor的execute2Future的自定義線程池Builder,LiteFlow提供了默認(rèn)的Builder main-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder #自定義請求ID的生成類,LiteFlow提供了默認(rèn)的生成類 request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator #并行節(jié)點的線程池Builder,LiteFlow提供了默認(rèn)的Builder thread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder #異步線程最長的等待時間(只用于when),默認(rèn)值為15000 when-max-wait-time: 15000 #異步線程最長的等待時間(只用于when),默認(rèn)值為MILLISECONDS,毫秒 when-max-wait-time-unit: MILLISECONDS #when節(jié)點全局異步線程池最大線程數(shù),默認(rèn)為16 when-max-workers: 16 #并行循環(huán)子項線程池最大線程數(shù),默認(rèn)為16 parallelLoop-max-workers: 16 #并行循環(huán)子項線程池等待隊列數(shù),默認(rèn)為512 parallelLoop-queue-limit: 512 #并行循環(huán)子項的線程池Builder,LiteFlow提供了默認(rèn)的Builder parallelLoop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder #when節(jié)點全局異步線程池等待隊列數(shù),默認(rèn)為512 when-queue-limit: 512 #是否在啟動的時候就解析規(guī)則,默認(rèn)為true parse-on-start: true #全局重試次數(shù),默認(rèn)為0 retry-count: 0 #是否支持不同類型的加載方式混用,默認(rèn)為false support-multiple-type: false #全局默認(rèn)節(jié)點執(zhí)行器 node-executor-class: com.yomahub.liteflow.flow.executor.DefaultNodeExecutor #是否打印執(zhí)行中過程中的日志,默認(rèn)為true print-execution-log: true #是否開啟本地文件監(jiān)聽,默認(rèn)為false enable-monitor-file: false #簡易監(jiān)控配置選項 monitor: #監(jiān)控是否開啟,默認(rèn)不開啟 enable-log: false #監(jiān)控隊列存儲大小,默認(rèn)值為200 queue-limit: 200 #監(jiān)控一開始延遲多少執(zhí)行,默認(rèn)值為300000毫秒,也就是5分鐘 delay: 300000 #監(jiān)控日志打印每過多少時間執(zhí)行一次,默認(rèn)值為300000毫秒,也就是5分鐘 period: 300000
規(guī)則文件的定義
同時,你得在resources
下的config/flow.el.xml
中定義規(guī)則:SpringBoot
在啟動時會自動裝載規(guī)則文件。
<?xml version="1.0" encoding="UTF-8"?> <flow> <chain name="chain1"> THEN(a, b, c); </chain> </flow>
執(zhí)行
聲明啟動類:
@SpringBootApplication //把你定義的組件掃入Spring上下文中 @ComponentScan({"com.xxx.xxx.cmp"}) public class LiteflowExampleApplication { public static void main(String[] args) { SpringApplication.run(LiteflowExampleApplication.class, args); } }
然后你就可以在Springboot
任意被Spring
托管的類中拿到flowExecutor
,進(jìn)行執(zhí)行鏈路:這個DefaultContext
是默認(rèn)的上下文,用戶可以用最自己的任意Bean
當(dāng)做上下文傳入,如果需要傳入自己的上下文,則需要傳用戶Bean
的Class
屬性
@Component public class YourClass{ @Resource private FlowExecutor flowExecutor; public void testConfig(){ LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); } }
六、數(shù)據(jù)上下文
在執(zhí)行器執(zhí)行流程時會分配數(shù)據(jù)上下文實例給這個請求。不同請求的數(shù)據(jù)上下文實例是完全隔離的。里面存放著此請求所有的用戶數(shù)據(jù)。不同的組件之間是不傳遞參數(shù)的,所有的數(shù)據(jù)交互都是通過這個數(shù)據(jù)上下文來實現(xiàn)的。數(shù)據(jù)上下文這個概念在LiteFlow
框架中非常重要,你所有的業(yè)務(wù)數(shù)據(jù)都是放在數(shù)據(jù)上下文中。要做到可編排,一定是消除每個組件差異性的。如果每個組件出參入?yún)⒍疾灰恢?,那就沒法編排了。
LiteFlow
對此有獨特的設(shè)計理念,平時我們寫瀑布流的程序時,A調(diào)用B,那A一定要把B所需要的參數(shù)傳遞給B,而在LiteFlow
框架體系中,每個組件的定義中是不需要接受參數(shù)的,也無任何返回的。每個組件只需要從數(shù)據(jù)上下文中獲取自己關(guān)心的數(shù)據(jù)即可,而不用關(guān)心此數(shù)據(jù)是由誰提供的,同樣的,每個組件也只要把自己執(zhí)行所產(chǎn)生的結(jié)果數(shù)據(jù)放到數(shù)據(jù)上下文中即可,也不用關(guān)心此數(shù)據(jù)到底是提供給誰用的。這樣一來,就從數(shù)據(jù)層面一定程度的解耦了。從而達(dá)到可編排的目的。關(guān)于這個理念,也在LiteFlow
簡介中的設(shè)計原則有提到過,給了一個形象的例子,大家可以再去看看。
一旦在數(shù)據(jù)上下文中放入數(shù)據(jù),整個鏈路中的任一節(jié)點都是可以取到的。
默認(rèn)上下文
LiteFlow
提供了一個默認(rèn)的數(shù)據(jù)上下文的實現(xiàn):DefaultContext
。這個默認(rèn)的實現(xiàn)其實里面主要存儲數(shù)據(jù)的容器就是一個Map
。你可以通過DefaultContext
中的setData
方法放入數(shù)據(jù),通過getData
方法獲得數(shù)據(jù)。
::: warningDefaultContext
雖然可以用,但是在實際業(yè)務(wù)中,用這個會存在大量的弱類型,存取數(shù)據(jù)的時候都要進(jìn)行強(qiáng)轉(zhuǎn),頗為不方便。所以官方建議你自己去實現(xiàn)自己的數(shù)據(jù)上下文。
:::
自定義上下文
在一個流程中,總會有一些初始的參數(shù),比如訂單號,用戶Id
等等一些的初始參數(shù)。這時候需要通過以下方法的第二個參數(shù)傳入:
//參數(shù)為流程ID,無初始流程入?yún)?,上下文類型為默認(rèn)的DefaultContext public LiteflowResponse execute2Resp(String chainId) //第一個參數(shù)為流程ID,第二個參數(shù)為流程入?yún)?。上下文類型為默認(rèn)的DefaultContext public LiteflowResponse execute2Resp(String chainId, Object param); //第一個參數(shù)為流程ID,第二個參數(shù)為流程入?yún)ⅲ竺婵梢詡魅攵鄠€上下文class public LiteflowResponse execute2Resp(String chainId, Object param, Class<?>... contextBeanClazzArray) //第一個參數(shù)為流程ID,第二個參數(shù)為流程入?yún)ⅲ竺婵梢詡魅攵鄠€上下文的Bean public LiteflowResponse execute2Resp(String chainId, Object param, Object... contextBeanArray)
你可以用你自己的任意的Bean
當(dāng)做上下文進(jìn)行傳入。LiteFlow
對上下文的Bean
沒有任何要求。自己定義的上下文實質(zhì)上就是一個最簡單的值對象,自己定義的上下文因為是強(qiáng)類型,更加貼合業(yè)務(wù)。你可以像這樣進(jìn)行傳入:
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始參數(shù), CustomContext.class);
傳入之后,LiteFlow
會在調(diào)用時進(jìn)行初始化,給這個上下文分配唯一的實例。你在組件之中可以這樣去獲得這個上下文實例:
@LiteflowComponent("yourCmpId") public class YourCmp extends NodeComponent { @Override public void process() { OrderContext orderContext = this.getContextBean(OrderContext.class); UserContext userContext = this.getContextBean(UserContext.class); SignContext signContext = this.getContextBean(SignContext.class); //如果你只想獲取第一個上下文,第一個上下文是OrderContext,那么也可以用這個方法 //OrderContext orderContext = this.getFirstContextBean(); ... } }
多上下文
LiteFlow
在新版本中支持了多上下文,在執(zhí)行的時候同時初始化你傳入的多個上下文。在組件里也可以根據(jù)class
類型很方便的拿到。你可以像這樣進(jìn)行傳入:
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始參數(shù), OrderContext.class, UserContext.class, SignContext.class);
在組件之中可以這樣去獲得這個上下文實例:
@LiteflowComponent("yourCmpId") public class YourCmp extends NodeComponent { @Override public void process() { OrderContext orderContext = this.getContextBean(OrderContext.class); UserContext userContext = this.getContextBean(UserContext.class); SignContext signContext = this.getContextBean(SignContext.class); //如果你只想獲取第一個上下文,第一個上下文是OrderContext,那么也可以用這個方法 //OrderContext orderContext = this.getFirstContextBean(); ... } }
用初始化好的上下文傳入
LiteFlow
從2.8.4
版本開始,允許用戶傳入一個或多個已經(jīng)初始化好的bean
作為上下文,而不是傳入class
對象。在拿到FlowExecutor
之后,你可以像如下一樣,傳入已經(jīng)初始化好的bean
作為上下文(當(dāng)然也支持多上下文,這里只演示單上下文):
OrderContext orderContext = new OrderContext(); orderContext.setOrderNo("SO11223344"); LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, orderContext);
::: warning
框架并不支持上下文bean
和class
混傳,你要么都傳bean
,要么都傳class
。
:::
七、異步Future
public Future<LiteflowResponse> execute2Future(String chainId, Object param, Class<?>... contextBeanClazzArray)
如果調(diào)用這個方法,那就是無阻塞的,想要拿到response
,請用得到的future.get()
就可以了。同時,主執(zhí)行器在這個模式下的線程數(shù)和線程池也可以自定義,具體配置如下,LiteFlow
已經(jīng)設(shè)置了預(yù)設(shè)值,你也可自己定義。
liteflow.main-executor-works=64 liteflow.main-executor-class=com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder
如果你定義了自定義線程池,你需新建一個類,然后實現(xiàn)ExecutorBuilder
接口:
public class CustomThreadBuilder implements ExecutorBuilder { @Override public ExecutorService buildExecutor() { return Executors.newCachedThreadPool(); } }
八、規(guī)則寫法 串行編排
如果你要依次執(zhí)行a,b,c,d
四個組件,你可以用THEN關(guān)鍵字,需要注意的是,THEN
必須大寫。
<chain name="chain1"> THEN(a, b, c, d); </chain>
并行編排
如果你要并行執(zhí)行a,b,c
三個組件,你可以用WHEN
關(guān)鍵字,需要注意的是,WHEN
必須大寫。
<chain name="chain1"> WHEN(a, b, c); </chain>
和串行嵌套起來:讓我們把THEN和WHEN結(jié)合起來用,看一個示例:b,c,d
默認(rèn)并行都執(zhí)行完畢后,才會執(zhí)行e
。
<chain name="chain1"> THEN( a, WHEN(b, c, d), e ); </chain>
上面的示例應(yīng)該很好理解吧,那么再看一個示例:
<chain name="chain1"> THEN( a, WHEN(b, THEN(c, d)), e ); </chain>
忽略錯誤: WHEN
關(guān)鍵字提供了一個子關(guān)鍵字ignoreError
(默認(rèn)為`false``)來提供忽略錯誤的特性,用法如下:
<chain name="chain1"> THEN( a, WHEN(b, c, d).ignoreError(true), e ); </chain>
設(shè)b,c,d
中任一一個節(jié)點有異常,那么最終e
仍舊會被執(zhí)行。
任一節(jié)點先執(zhí)行完則忽略其他: WHEN
關(guān)鍵字提供了一個子關(guān)鍵字any
(默認(rèn)為false
)用來提供并行流程中,任一條分支先執(zhí)行完即忽略其他分支,繼續(xù)執(zhí)行的特性。用法如下:假設(shè)e
節(jié)點先執(zhí)行完,那么不管其他分支是否執(zhí)行完,會立馬執(zhí)行節(jié)點f
。
<chain name="chain1"> THEN( a, WHEN(b, THEN(c, d), e).any(true), f ); </chain>
指定任意節(jié)點先執(zhí)行完則忽略其他: LiteFlow
從v2.11.1
開始,支持了并行編排中指定節(jié)點的執(zhí)行則忽略其他,WHEN
關(guān)鍵字新增子關(guān)鍵字must
(不可為空),可用于指定需等待執(zhí)行的任意節(jié)點,可以為1
個或者多個,若指定的所有節(jié)點率先完成,則繼續(xù)往下執(zhí)行,忽略同級別的其他任務(wù),用法如下:must
指定了b,c
,則b,c
是一定會被執(zhí)行完畢了,如果b,c
執(zhí)行完畢了后d
還未執(zhí)行完,則忽略,直接執(zhí)行下一個組件f
。
<chain name="chain1"> THEN( a, WHEN(b, c, d).must(b, c), f ); </chain>
以上是單節(jié)點的用法,must
還可以指定一個或多個表達(dá)式。比如:WHEN
里有一個嵌套的THEN
,如果需要指定這個表達(dá)式,則需要給這個表達(dá)式設(shè)置一個id
,must
里需要指定這個id
,需要注意的是,must
里指定id
,需要用引號括起來。
<chain name="chain1"> THEN( a, WHEN(b, THEN(c, d).id("t1"), e).must(b, "t1"), f ); </chain>
開啟WHEN線程池隔離:
目前liteflow
設(shè)計里when
線程池,如果你不單獨設(shè)置自定義線程池,那么就會用默認(rèn)的線程池。而這個線程池,是所有的when
共同一個。LiteFlow從2.11.1
開始,提供一個liteflow.when-thread-pool-isolate
參數(shù),默認(rèn)為false
,如果設(shè)為true
,則會開啟WHEN
的線程池隔離機(jī)制,這意味著每一個when
都會有單獨的線程池。這個特性對于運行復(fù)雜的嵌套when
時是可以提升運行速度的且規(guī)避掉一些鎖的問題。
你可以如下配置來開啟:
liteflow.when-thread-pool-isolate=true
選擇編排
我們在寫業(yè)務(wù)邏輯的時候,通常會碰到選擇性問題,即,如果返回結(jié)果1,則進(jìn)入A
流程,如果返回結(jié)果2,則進(jìn)入B
流程,如果返回結(jié)果3,則進(jìn)入C
流程。在有些流程定義中也被定義為排他網(wǎng)關(guān)。這個通過LiteFLow
的表達(dá)式也非常容易實現(xiàn),你可以用SWITCH...TO
的組合關(guān)鍵字,注意的是SWITCH
必須大寫,to
大小寫均可。
如果,根據(jù)組件a
,來選擇執(zhí)行b,c,d
中的一個,你可以如下聲明:
@LiteflowComponent("a") public class ACmp extends NodeSwitchComponent { @Override public String processSwitch() throws Exception { System.out.println("Acomp executed!"); return "c"; } }
DEFAULT關(guān)鍵字: LiteFlow
從2.9.5
開始,對選擇編排新增了一個DEFAULT
關(guān)鍵字。用法為SWITCH...TO...DEFAULT
。比如如下表達(dá)式:
<chain name="chain1"> SWITCH(x).TO(a, b, c).DEFAULT(y); </chain>
如上表達(dá)式的x
如果返回非a,b,c
中的一個,則默認(rèn)選擇到y
。當(dāng)然DEFAULT
里面也可以是一個表達(dá)式。
選擇編排中的id
語法: 接下來展示一個SWITCH
中套THEN
和WHEN
的例子。如果你閱讀過選擇組件這一章,就應(yīng)該知道,LiteFlow
通過選擇組件的返回來確定該選擇什么。那么如果SWITCH
中套一個THEN
,那么選擇組件如果要選擇這個THEN
應(yīng)該返回什么呢?LiteFlow
中規(guī)定,每個表達(dá)式都可以有一個id
值,你可以設(shè)置id值來設(shè)置一個表達(dá)式的id
值。然后在選擇組件里返回這個id
即可。用法如下:
<chain name="chain1"> THEN( a, SWITCH(b).to( c, THEN(d, e).id("t1") ), f ); </chain>
如果你想選擇THEN
這個表達(dá)式,那么你可以在選擇節(jié)點里返回t1
:
@LiteflowComponent("b") public class BCmp extends NodeSwitchComponent { @Override public String processSwitch() throws Exception { //do your biz return "t1"; } }
選擇編排中的tag語法: 事實上,除了給表達(dá)式賦值id
屬性之外,你還可以給表達(dá)式賦值tag
屬性。用法如下:
<chain name="chain1"> THEN( a, SWITCH(b).to( c, THEN(d, e).tag("t1") ), f ); </chain>
如果你想選擇THEN
這個表達(dá)式,那么你可以在選擇節(jié)點里返回:
@LiteflowComponent("b") public class BCmp extends NodeSwitchComponent { @Override public String processSwitch() throws Exception { return "tag:t1"; //以下這種也是可以的 return ":t1"; } }
條件編排
條件編排是選擇編排一個變種,選擇編排是根據(jù)邏輯去選擇多個子項中的一項。而條件編排只有真和假2個子項,這處理某些業(yè)務(wù)的過程中非常有用。其實簡單來說,條件編排就是編程語言中的if else
。只不過在LiteFlow EL
語法中有一些不一樣的用法。以下IF
和ELIF
的第一個參數(shù)要求定義條件組件。
IF的二元表達(dá)式: 其中x
為條件節(jié)點,為真的情況下,執(zhí)行鏈路就為x->a->b
,為假鏈路就為x->b
。
<chain name="chain1"> THEN( IF(x, a), b ); </chain>
@Component("x") public class XCmp extends NodeIfComponent { @Override public boolean processIf() throws Exception { //do your biz return true; } }
IF的三元表達(dá)式: 其中x
為條件節(jié)點,為真的情況下,執(zhí)行鏈路就為x->a->c
,為假鏈路就為x->b->c
。
<chain name="chain1"> THEN( IF(x, a, b), c ); </chain>
ELIF表達(dá)式: ELIF
關(guān)鍵字的用法其實和java
語言的else if
類似,可以跟多個,和IF
二元表達(dá)式參數(shù)一樣,一般最后還會跟個ELSE
,用于多重條件的判斷:
<chain name="chain1"> IF(x1, a).ELIF(x2, b).ELIF(x3, c).ELIF(x4, d).ELSE(THEN(m, n)); </chain>
循環(huán)編排
FOR循環(huán): FOR
循環(huán)表達(dá)式用于固定次數(shù)的循環(huán),通常的用法為:
<chain name="chain1"> FOR(5).DO(THEN(a, b)); </chain>
上述表達(dá)式表示把a->b
這個鏈路固定循環(huán)了5
次。如果你在定義規(guī)則的時候并不確定要循環(huán)幾次,要在代碼運行的時候才知道。那你也可以這樣定義:
<chain name="chain1"> FOR(f).DO(THEN(a, b)); </chain>
其中f
這個節(jié)點需要為次數(shù)循環(huán)組件,返回一個int
循環(huán)次數(shù),f
節(jié)點的定義,需要繼承NodeForComponent
,需要實現(xiàn)processFor
方法:
@LiteflowComponent("f") public class FCmp extends NodeForComponent { @Override public int processFor() throws Exception { //這里根據(jù)業(yè)務(wù)去返回for的結(jié)果 } }
循環(huán)下標(biāo)獲?。宏P(guān)鍵字
FOR...DO...
中DO
里面的任意java
組件都可以通過this.getLoopIndex()
來獲得下標(biāo)。在腳本中通過_meta.loopIndex
來獲取。
WHILE循環(huán):
<chain name="chain1"> WHILE(w).DO(THEN(a, b)); </chain>
其中w
這個節(jié)點需要為條件循環(huán)組件,返回一個布爾值,為true
則繼續(xù)循環(huán)
@LiteflowComponent("w") public class WCmp extends NodeWhileComponent { @Override public boolean processWhile() throws Exception { //這里根據(jù)業(yè)務(wù)去返回while的結(jié)果 } }
循環(huán)下標(biāo)獲?。宏P(guān)鍵字
WHILE...DO...
中DO
里面的任意節(jié)點都可以通過this.getLoopIndex()
來獲得下標(biāo)。在腳本中通過_meta.loopIndex
來獲取。
ITERATOR迭代循環(huán)
<chain name="chain1"> ITERATOR(x).DO(THEN(a, b)); </chain>
其中x
這個節(jié)點需要為迭代循環(huán)組件,返回一個迭代器:x
節(jié)點的定義,需要繼承NodeIteratorComponent
,需要實現(xiàn)processIterator
方法:
@LiteflowComponent("x") public class XCmp extends NodeIteratorComponent { @Override public Iterator<?> processIterator() throws Exception { List<String> list = ListUtil.toList("jack", "mary", "tom"); return list.iterator(); } }
BREAK
LiteFlow
同樣也支持BREAK
語法,代表退出循環(huán)。BREAK
關(guān)鍵字可以跟在FOR
和WHILE
后面,通常用法為:
<chain name="chain1"> FOR(f).DO(THEN(a, b)).BREAK(c); </chain> <chain name="chain1"> WHILE(w).DO(THEN(a, b)).BREAK(c); </chain>
其中c
這個節(jié)點需要為退出循環(huán)組件,返回一個布爾值,為true
則退出循環(huán)。c
節(jié)點的定義,需要繼承NodeBreakComponent
,需要實現(xiàn)processBreak
方法:
@LiteflowComponent("c") public class CCmp extends NodeBreakComponent { @Override public boolean processBreak() throws Exception { //這里根據(jù)業(yè)務(wù)去返回break的結(jié)果 } }
BREAK
關(guān)鍵字是在每次循環(huán)的末尾進(jìn)行判斷的。
到此這篇關(guān)于SpringBoot——LiteFlow引擎框架的文章就介紹到這了,更多相關(guān)SpringBoot LiteFlow引擎內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
elasticsearch 8.2.3 安裝及springboot簡單使用
這篇文章主要介紹了elasticsearch 8.2.3 安裝及springboot簡單使用,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06關(guān)于Idea中的.properties文件顯示問題
這篇文章主要介紹了關(guān)于Idea中的.properties文件顯示問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07Spring Boot 與 Kotlin 使用JdbcTemplate連接MySQL數(shù)據(jù)庫的方法
本文介紹在Spring Boot基礎(chǔ)下配置數(shù)據(jù)源和通過 JdbcTemplate 編寫數(shù)據(jù)訪問的示例。感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-01-01詳解將Eclipse代碼導(dǎo)入到AndroidStudio的兩種方式
本篇文章主要介紹了詳解將Eclipse代碼導(dǎo)入到AndroidStudio的兩種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12Java日期時間處理問題(從Date、Calendar到SimpleDateFormat)
這篇文章主要介紹了Java日期時間處理深度解析(從Date、Calendar到SimpleDateFormat),我們詳細(xì)討論了Java中的日期和時間處理,包括Date、Calendar和SimpleDateFormat類的使用,以及Java?8引入的新的日期時間API的優(yōu)勢,需要的朋友可以參考下2024-08-08java并發(fā)編程專題(十一)----(JUC原子類)數(shù)組類型詳解
這篇文章主要介紹了JAVA JUC原子類 數(shù)組類型詳解的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07