欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot?LiteFlow引擎框架使用原理解析

 更新時(shí)間:2024年03月05日 15:13:06   作者:程序猿進(jìn)階  
LiteFlow是一個(gè)輕量且強(qiáng)大的國(guó)產(chǎn)規(guī)則引擎框架,可用于復(fù)雜的組件化業(yè)務(wù)的編排領(lǐng)域,本文給大家介紹SpringBoot?LiteFlow引擎框架的相關(guān)操作,感興趣的朋友跟隨小編一起看看吧

一、LiteFlow 簡(jiǎn)介

LiteFlow是一個(gè)輕量且強(qiáng)大的國(guó)產(chǎn)規(guī)則引擎框架,可用于復(fù)雜的組件化業(yè)務(wù)的編排領(lǐng)域。幫助系統(tǒng)變得更加絲滑且靈活。利用LiteFlow,你可以將瀑布流式的代碼,轉(zhuǎn)變成以組件為核心概念的代碼結(jié)構(gòu),這種結(jié)構(gòu)的好處是可以任意編排,組件與組件之間是解耦的,組件可以用腳本來定義,組件之間的流轉(zhuǎn)全靠規(guī)則來驅(qū)動(dòng)。LiteFlow擁有開源規(guī)則引擎最為簡(jiǎn)單的DSL語(yǔ)法。 LiteFlow官網(wǎng)

LiteFlow2020年正式開源,2021年獲得開源中國(guó)年度最受歡迎開源軟件殊榮。于2022年獲得Gitee最有價(jià)值開源項(xiàng)目GVP榮譽(yù)。是一個(gè)正處在高速發(fā)展中的開源項(xiàng)目。LiteFlow是一個(gè)由社區(qū)驅(qū)動(dòng)的項(xiàng)目,擁有一個(gè)2500多人的使用者社區(qū)。雖然相比Acitiviti、Flowable來說,LiteFlow的知名度要低得多,功能也沒有這些知名成熟引擎那么強(qiáng)大,但LiteFlow還是有諸多優(yōu)點(diǎn),能夠滿足你絕大部分的場(chǎng)景。這些優(yōu)點(diǎn)包括:
【1】規(guī)則多樣化: 規(guī)則支持xmljson、yml三種規(guī)則文件寫法方式。
【2】使用便捷: 引幾個(gè)jar包、實(shí)現(xiàn)幾個(gè)接口、寫一個(gè)流程編排文件,就能運(yùn)行。
【3】編排豐富: 支持串行、并行、選擇、循環(huán)、異常處理、嵌套等各種編排方式。
【4】事件監(jiān)聽: 支持事件觸發(fā)和狀態(tài)變化監(jiān)聽,可以方便地?cái)U(kuò)展和定制工作流處理邏輯。
【5】異步超時(shí): 支持異步執(zhí)行和超時(shí)控制,可以提高系統(tǒng)的并發(fā)處理能力和穩(wěn)定性。
【6】支持腳本: 支持各種主流腳本語(yǔ)言。
【7】配置源豐富: 支持將流程定義放到ZK/DB/Etcd/Nacos/Redis/Apollo和自定義擴(kuò)展等。相當(dāng)于可以實(shí)現(xiàn)動(dòng)態(tài)配置更改。
【8】定制化: 高度可定制化,用戶可以根據(jù)自己的需求自由擴(kuò)展和定制LiteFlow的各種組件和功能。
【9】支持眾多腳本語(yǔ)言: LiteFlow的腳本組件,支持眾多腳本語(yǔ)言Groovy/JavaScript/QLExpress/Python/Lua/Aviator/Java,完全和Java打通,你可以用腳本來實(shí)現(xiàn)任何邏輯。
【10】?jī)?yōu)雅熱刷新機(jī)制: 規(guī)則變化,無需重啟您的應(yīng)用,即時(shí)改變應(yīng)用的規(guī)則。高并發(fā)下不會(huì)因?yàn)樗⑿乱?guī)則導(dǎo)致正在執(zhí)行的規(guī)則有任何錯(cuò)亂。
【11】支持廣泛: 不管你的項(xiàng)目是不是基于Springboot,Spring還是任何其他java框架構(gòu)建,LiteFlow都能游刃有余。
【12】上下文隔離機(jī)制: 可靠的上下文隔離機(jī)制,你無需擔(dān)心高并發(fā)情況下的數(shù)據(jù)串流。
【13】性能卓越: 框架本身幾乎不消耗額外性能,性能取決你的組件執(zhí)行效率。
【14】自帶簡(jiǎn)單監(jiān)控: 框架內(nèi)自帶一個(gè)命令行的監(jiān)控,能夠知道每個(gè)組件的運(yùn)行耗時(shí)排行。

適合使用的這項(xiàng)技術(shù)的系統(tǒng)

在每個(gè)公司的系統(tǒng)中,總有一些擁有復(fù)雜業(yè)務(wù)邏輯的系統(tǒng),這些系統(tǒng)承載著核心業(yè)務(wù)邏輯,幾乎每個(gè)需求都和這些核心業(yè)務(wù)有關(guān),這些核心業(yè)務(wù)業(yè)務(wù)邏輯冗長(zhǎng),涉及內(nèi)部邏輯運(yùn)算,緩存操作,持久化操作,外部資源調(diào)取,內(nèi)部其他系統(tǒng)RPC調(diào)用等等。時(shí)間一長(zhǎng),項(xiàng)目幾經(jīng)易手,維護(hù)成本就會(huì)越來越高。各種硬代碼判斷,分支條件越來越多。代碼的抽象,復(fù)用率也越來越低,各個(gè)模塊之間的耦合度很高。一小段邏輯的變動(dòng),會(huì)影響到其他模塊,需要進(jìn)行完整回歸測(cè)試來驗(yàn)證。如要靈活改變業(yè)務(wù)流程的順序,則要進(jìn)行代碼大改動(dòng)進(jìn)行抽象,重新寫方法。實(shí)時(shí)熱變更業(yè)務(wù)流程,幾乎很難實(shí)現(xiàn)。

如何打破僵局?LiteFlow為解耦邏輯而生,為編排而生,在使用LiteFlow之后,你會(huì)發(fā)現(xiàn)打造一個(gè)低耦合,靈活的系統(tǒng)會(huì)變得易如反掌!

二、LiteFlow 原理

如果你要對(duì)復(fù)雜業(yè)務(wù)邏輯進(jìn)行新寫或者重構(gòu),用LiteFlow最合適不過。它是一個(gè)編排式的規(guī)則引擎框架,組件編排,幫助解耦業(yè)務(wù)代碼,讓每一個(gè)業(yè)務(wù)片段都是一個(gè)組件。

LiteFlow的核心是“流程即代碼”,即將業(yè)務(wù)流程和代碼結(jié)構(gòu)緊密耦合在一起。LiteFlow采用基于XML文件的流程定義方式,通過定義流程節(jié)點(diǎn)和連線來描述整個(gè)工作流程。每個(gè)流程節(jié)點(diǎn)都對(duì)應(yīng)著Java代碼中的一個(gè)方法,而連線則對(duì)應(yīng)著方法之間的調(diào)用關(guān)系。這樣一來,我們就可以非常直觀地看到整個(gè)業(yè)務(wù)流程的處理過程,而且在修改流程時(shí)也更加方便快捷。

組件可實(shí)時(shí)熱更替,也可以給編排好的邏輯流里實(shí)時(shí)增加一個(gè)組件,從而改變你的業(yè)務(wù)邏輯。

編排語(yǔ)法強(qiáng)大到可以編排出任何你想要的邏輯流程例如:

三、使用場(chǎng)景

LiteFlow適用于哪些場(chǎng)景: LiteFlow適用于擁有復(fù)雜邏輯的業(yè)務(wù),比如說價(jià)格引擎,下單流程等,這些業(yè)務(wù)往往都擁有很多步驟,這些步驟完全可以按照業(yè)務(wù)粒度拆分成一個(gè)個(gè)獨(dú)立的組件,進(jìn)行裝配復(fù)用變更。使用LiteFlow,你會(huì)得到一個(gè)靈活度高,擴(kuò)展性很強(qiáng)的系統(tǒng)。因?yàn)榻M件之間相互獨(dú)立,也可以避免改一處而動(dòng)全身的這樣的風(fēng)險(xiǎn)。

LiteFlow不適用于哪些場(chǎng)景: LiteFlow不適合角色任務(wù)之間的流轉(zhuǎn),類似于審批流,A審批完應(yīng)該是B審批,然后再流轉(zhuǎn)到C角色。這里申明下,LiteFlow只做基于邏輯的流轉(zhuǎn),而不做基于角色任務(wù)的流轉(zhuǎn)。如果你想做基于角色任務(wù)的流轉(zhuǎn),推薦使用flowable,activiti這2個(gè)框架。

四、JDK支持情況

LiteFlow要求的最低的JDK版本為8,支持JDK8~JDK17所有的版本。如果你使用JDK11以上,確保LiteFlow的版本為v2.10.6及其以上版本。因?yàn)?code>LiteFlow從v2.10.6開始,對(duì)JDK11JDK17進(jìn)行了詳細(xì)的用例測(cè)試,通過了全部的900多個(gè)測(cè)試用例。而在v2.10.6以下版本,在JDK11以上是未經(jīng)過測(cè)試用例保障的。特別需要注意的是,如果你使用JDK11及其以上的版本,請(qǐng)確保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依賴包,提供自動(dòng)裝配功能

<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
    <version>2.11.3</version>
</dependency>

組件定義

在依賴了以上jar包后,你需要定義并實(shí)現(xiàn)一些組件,確保SpringBoot會(huì)掃描到這些組件并注冊(cè)進(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配置文件

然后,在你的SpringBootapplication.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é)點(diǎn),只有使用zk作為配置源的時(shí)候才起作用,默認(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
  #自定義請(qǐng)求ID的生成類,LiteFlow提供了默認(rèn)的生成類
  request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator
  #并行節(jié)點(diǎn)的線程池Builder,LiteFlow提供了默認(rèn)的Builder
  thread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder
  #異步線程最長(zhǎng)的等待時(shí)間(只用于when),默認(rèn)值為15000
  when-max-wait-time: 15000
  #異步線程最長(zhǎng)的等待時(shí)間(只用于when),默認(rèn)值為MILLISECONDS,毫秒
  when-max-wait-time-unit: MILLISECONDS
  #when節(jié)點(diǎn)全局異步線程池最大線程數(shù),默認(rèn)為16
  when-max-workers: 16
  #并行循環(huán)子項(xiàng)線程池最大線程數(shù),默認(rèn)為16
  parallelLoop-max-workers: 16
  #并行循環(huán)子項(xiàng)線程池等待隊(duì)列數(shù),默認(rèn)為512
  parallelLoop-queue-limit: 512
  #并行循環(huán)子項(xiàng)的線程池Builder,LiteFlow提供了默認(rèn)的Builder
  parallelLoop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder
  #when節(jié)點(diǎn)全局異步線程池等待隊(duì)列數(shù),默認(rèn)為512
  when-queue-limit: 512
  #是否在啟動(dòng)的時(shí)候就解析規(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é)點(diǎn)執(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)易監(jiān)控配置選項(xiàng)
  monitor:
    #監(jiān)控是否開啟,默認(rèn)不開啟
    enable-log: false
    #監(jiān)控隊(duì)列存儲(chǔ)大小,默認(rèn)值為200
    queue-limit: 200
    #監(jiān)控一開始延遲多少執(zhí)行,默認(rèn)值為300000毫秒,也就是5分鐘
    delay: 300000
    #監(jiān)控日志打印每過多少時(shí)間執(zhí)行一次,默認(rèn)值為300000毫秒,也就是5分鐘
    period: 300000

規(guī)則文件的定義

同時(shí),你得在resources下的config/flow.el.xml中定義規(guī)則:SpringBoot在啟動(dòng)時(shí)會(huì)自動(dòng)裝載規(guī)則文件。

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="chain1">
        THEN(a, b, c);
    </chain>
</flow>

執(zhí)行

聲明啟動(dòng)類:

@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í)行鏈路:這個(gè)DefaultContext是默認(rèn)的上下文,用戶可以用最自己的任意Bean當(dāng)做上下文傳入,如果需要傳入自己的上下文,則需要傳用戶BeanClass屬性

@Component
public class YourClass{
    @Resource
    private FlowExecutor flowExecutor;
    public void testConfig(){
        LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
    }
}

六、數(shù)據(jù)上下文

在執(zhí)行器執(zhí)行流程時(shí)會(huì)分配數(shù)據(jù)上下文實(shí)例給這個(gè)請(qǐng)求。不同請(qǐng)求的數(shù)據(jù)上下文實(shí)例是完全隔離的。里面存放著此請(qǐng)求所有的用戶數(shù)據(jù)。不同的組件之間是不傳遞參數(shù)的,所有的數(shù)據(jù)交互都是通過這個(gè)數(shù)據(jù)上下文來實(shí)現(xiàn)的。數(shù)據(jù)上下文這個(gè)概念在LiteFlow框架中非常重要,你所有的業(yè)務(wù)數(shù)據(jù)都是放在數(shù)據(jù)上下文中。要做到可編排,一定是消除每個(gè)組件差異性的。如果每個(gè)組件出參入?yún)⒍疾灰恢?,那就沒法編排了。

LiteFlow對(duì)此有獨(dú)特的設(shè)計(jì)理念,平時(shí)我們寫瀑布流的程序時(shí),A調(diào)用B,那A一定要把B所需要的參數(shù)傳遞給B,而在LiteFlow框架體系中,每個(gè)組件的定義中是不需要接受參數(shù)的,也無任何返回的。每個(gè)組件只需要從數(shù)據(jù)上下文中獲取自己關(guān)心的數(shù)據(jù)即可,而不用關(guān)心此數(shù)據(jù)是由誰(shuí)提供的,同樣的,每個(gè)組件也只要把自己執(zhí)行所產(chǎn)生的結(jié)果數(shù)據(jù)放到數(shù)據(jù)上下文中即可,也不用關(guān)心此數(shù)據(jù)到底是提供給誰(shuí)用的。這樣一來,就從數(shù)據(jù)層面一定程度的解耦了。從而達(dá)到可編排的目的。關(guān)于這個(gè)理念,也在LiteFlow簡(jiǎn)介中的設(shè)計(jì)原則有提到過,給了一個(gè)形象的例子,大家可以再去看看。

一旦在數(shù)據(jù)上下文中放入數(shù)據(jù),整個(gè)鏈路中的任一節(jié)點(diǎn)都是可以取到的。

默認(rèn)上下文

LiteFlow提供了一個(gè)默認(rèn)的數(shù)據(jù)上下文的實(shí)現(xiàn):DefaultContext。這個(gè)默認(rèn)的實(shí)現(xiàn)其實(shí)里面主要存儲(chǔ)數(shù)據(jù)的容器就是一個(gè)Map。你可以通過DefaultContext中的setData方法放入數(shù)據(jù),通過getData方法獲得數(shù)據(jù)。

::: warning
DefaultContext雖然可以用,但是在實(shí)際業(yè)務(wù)中,用這個(gè)會(huì)存在大量的弱類型,存取數(shù)據(jù)的時(shí)候都要進(jìn)行強(qiáng)轉(zhuǎn),頗為不方便。所以官方建議你自己去實(shí)現(xiàn)自己的數(shù)據(jù)上下文。
:::

自定義上下文

在一個(gè)流程中,總會(huì)有一些初始的參數(shù),比如訂單號(hào),用戶Id等等一些的初始參數(shù)。這時(shí)候需要通過以下方法的第二個(gè)參數(shù)傳入:

//參數(shù)為流程ID,無初始流程入?yún)?,上下文類型為默認(rèn)的DefaultContext
public LiteflowResponse execute2Resp(String chainId)
//第一個(gè)參數(shù)為流程ID,第二個(gè)參數(shù)為流程入?yún)?。上下文類型為默認(rèn)的DefaultContext
public LiteflowResponse execute2Resp(String chainId, Object param);
//第一個(gè)參數(shù)為流程ID,第二個(gè)參數(shù)為流程入?yún)?,后面可以傳入多個(gè)上下文class
public LiteflowResponse execute2Resp(String chainId, Object param, Class<?>... contextBeanClazzArray)
//第一個(gè)參數(shù)為流程ID,第二個(gè)參數(shù)為流程入?yún)?,后面可以傳入多個(gè)上下文的Bean
public LiteflowResponse execute2Resp(String chainId, Object param, Object... contextBeanArray)

你可以用你自己的任意的Bean當(dāng)做上下文進(jìn)行傳入。LiteFlow對(duì)上下文的Bean沒有任何要求。自己定義的上下文實(shí)質(zhì)上就是一個(gè)最簡(jiǎn)單的值對(duì)象,自己定義的上下文因?yàn)槭菑?qiáng)類型,更加貼合業(yè)務(wù)。你可以像這樣進(jìn)行傳入:

LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始參數(shù), CustomContext.class);

傳入之后,LiteFlow會(huì)在調(diào)用時(shí)進(jìn)行初始化,給這個(gè)上下文分配唯一的實(shí)例。你在組件之中可以這樣去獲得這個(gè)上下文實(shí)例:

@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);
		//如果你只想獲取第一個(gè)上下文,第一個(gè)上下文是OrderContext,那么也可以用這個(gè)方法
		//OrderContext orderContext = this.getFirstContextBean();
		...
	}
}

多上下文

LiteFlow在新版本中支持了多上下文,在執(zhí)行的時(shí)候同時(shí)初始化你傳入的多個(gè)上下文。在組件里也可以根據(jù)class類型很方便的拿到。你可以像這樣進(jìn)行傳入:

LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始參數(shù), OrderContext.class, UserContext.class, SignContext.class);

在組件之中可以這樣去獲得這個(gè)上下文實(shí)例:

@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);
		//如果你只想獲取第一個(gè)上下文,第一個(gè)上下文是OrderContext,那么也可以用這個(gè)方法
		//OrderContext orderContext = this.getFirstContextBean();
		...
	}
}

用初始化好的上下文傳入

LiteFlow2.8.4版本開始,允許用戶傳入一個(gè)或多個(gè)已經(jīng)初始化好的bean作為上下文,而不是傳入class對(duì)象。在拿到FlowExecutor之后,你可以像如下一樣,傳入已經(jīng)初始化好的bean作為上下文(當(dāng)然也支持多上下文,這里只演示單上下文):

OrderContext orderContext = new OrderContext();
orderContext.setOrderNo("SO11223344");
LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, orderContext);

::: warning
框架并不支持上下文beanclass混傳,你要么都傳bean,要么都傳class。
:::

七、異步Future

public Future<LiteflowResponse> execute2Future(String chainId, Object param, Class<?>... contextBeanClazzArray)

如果調(diào)用這個(gè)方法,那就是無阻塞的,想要拿到response,請(qǐng)用得到的future.get()就可以了。同時(shí),主執(zhí)行器在這個(gè)模式下的線程數(shù)和線程池也可以自定義,具體配置如下,LiteFlow已經(jīng)設(shè)置了預(yù)設(shè)值,你也可自己定義。

liteflow.main-executor-works=64
liteflow.main-executor-class=com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder

如果你定義了自定義線程池,你需新建一個(gè)類,然后實(shí)現(xiàn)ExecutorBuilder接口:

public class CustomThreadBuilder implements ExecutorBuilder {
    @Override
    public ExecutorService buildExecutor() {
        return Executors.newCachedThreadPool();
    }
}

八、規(guī)則寫法 串行編排

如果你要依次執(zhí)行a,b,c,d四個(gè)組件,你可以用THEN關(guān)鍵字,需要注意的是,THEN必須大寫。

<chain name="chain1">
    THEN(a, b, c, d);
</chain>

并行編排

如果你要并行執(zhí)行a,b,c三個(gè)組件,你可以用WHEN關(guān)鍵字,需要注意的是,WHEN必須大寫。

<chain name="chain1">
    WHEN(a, b, c);
</chain>

和串行嵌套起來:讓我們把THEN和WHEN結(jié)合起來用,看一個(gè)示例:b,c,d默認(rèn)并行都執(zhí)行完畢后,才會(huì)執(zhí)行e。

<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d),
        e
    );
</chain>

上面的示例應(yīng)該很好理解吧,那么再看一個(gè)示例:

<chain name="chain1">
    THEN(
        a,
        WHEN(b, THEN(c, d)),
        e
    );
</chain>

忽略錯(cuò)誤: WHEN關(guān)鍵字提供了一個(gè)子關(guān)鍵字ignoreError(默認(rèn)為`false``)來提供忽略錯(cuò)誤的特性,用法如下:

<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d).ignoreError(true),
        e
    );
</chain>

設(shè)b,c,d中任一一個(gè)節(jié)點(diǎn)有異常,那么最終e仍舊會(huì)被執(zhí)行。

任一節(jié)點(diǎn)先執(zhí)行完則忽略其他: WHEN關(guān)鍵字提供了一個(gè)子關(guān)鍵字any(默認(rèn)為false)用來提供并行流程中,任一條分支先執(zhí)行完即忽略其他分支,繼續(xù)執(zhí)行的特性。用法如下:假設(shè)e節(jié)點(diǎn)先執(zhí)行完,那么不管其他分支是否執(zhí)行完,會(huì)立馬執(zhí)行節(jié)點(diǎn)f。

<chain name="chain1">
    THEN(
        a,
        WHEN(b, THEN(c, d), e).any(true),
        f
    );
</chain>

指定任意節(jié)點(diǎn)先執(zhí)行完則忽略其他: LiteFlowv2.11.1開始,支持了并行編排中指定節(jié)點(diǎn)的執(zhí)行則忽略其他,WHEN關(guān)鍵字新增子關(guān)鍵字must(不可為空),可用于指定需等待執(zhí)行的任意節(jié)點(diǎn),可以為1個(gè)或者多個(gè),若指定的所有節(jié)點(diǎn)率先完成,則繼續(xù)往下執(zhí)行,忽略同級(jí)別的其他任務(wù),用法如下:must指定了b,c,則b,c是一定會(huì)被執(zhí)行完畢了,如果b,c執(zhí)行完畢了后d還未執(zhí)行完,則忽略,直接執(zhí)行下一個(gè)組件f。

<chain name="chain1">
    THEN(
        a,
        WHEN(b, c, d).must(b, c),
        f
    );
</chain>

以上是單節(jié)點(diǎn)的用法,must還可以指定一個(gè)或多個(gè)表達(dá)式。比如:WHEN里有一個(gè)嵌套的THEN,如果需要指定這個(gè)表達(dá)式,則需要給這個(gè)表達(dá)式設(shè)置一個(gè)id,must里需要指定這個(gè)id,需要注意的是,must里指定id,需要用引號(hào)括起來。

<chain name="chain1">
    THEN(
        a,
        WHEN(b, THEN(c, d).id("t1"), e).must(b, "t1"),
        f
    );
</chain>

開啟WHEN線程池隔離:
目前liteflow設(shè)計(jì)里when線程池,如果你不單獨(dú)設(shè)置自定義線程池,那么就會(huì)用默認(rèn)的線程池。而這個(gè)線程池,是所有的when共同一個(gè)。LiteFlow從2.11.1開始,提供一個(gè)liteflow.when-thread-pool-isolate參數(shù),默認(rèn)為false,如果設(shè)為true,則會(huì)開啟WHEN的線程池隔離機(jī)制,這意味著每一個(gè)when都會(huì)有單獨(dú)的線程池。這個(gè)特性對(duì)于運(yùn)行復(fù)雜的嵌套when時(shí)是可以提升運(yùn)行速度的且規(guī)避掉一些鎖的問題。

你可以如下配置來開啟:

liteflow.when-thread-pool-isolate=true

選擇編排

我們?cè)趯憳I(yè)務(wù)邏輯的時(shí)候,通常會(huì)碰到選擇性問題,即,如果返回結(jié)果1,則進(jìn)入A流程,如果返回結(jié)果2,則進(jìn)入B流程,如果返回結(jié)果3,則進(jìn)入C流程。在有些流程定義中也被定義為排他網(wǎng)關(guān)。這個(gè)通過LiteFLow的表達(dá)式也非常容易實(shí)現(xiàn),你可以用SWITCH...TO的組合關(guān)鍵字,注意的是SWITCH必須大寫,to大小寫均可。

如果,根據(jù)組件a,來選擇執(zhí)行b,c,d中的一個(gè),你可以如下聲明:

在這里插入圖片描述

@LiteflowComponent("a")
public class ACmp extends NodeSwitchComponent {
    @Override
    public String processSwitch() throws Exception {
        System.out.println("Acomp executed!");
        return "c";
    }
}

DEFAULT關(guān)鍵字: LiteFlow2.9.5開始,對(duì)選擇編排新增了一個(gè)DEFAULT關(guān)鍵字。用法為SWITCH...TO...DEFAULT。比如如下表達(dá)式:

<chain name="chain1">
    SWITCH(x).TO(a, b, c).DEFAULT(y);
</chain>

如上表達(dá)式的x如果返回非a,b,c中的一個(gè),則默認(rèn)選擇到y。當(dāng)然DEFAULT里面也可以是一個(gè)表達(dá)式。

選擇編排中的id語(yǔ)法: 接下來展示一個(gè)SWITCH中套THENWHEN的例子。如果你閱讀過選擇組件這一章,就應(yīng)該知道,LiteFlow通過選擇組件的返回來確定該選擇什么。那么如果SWITCH中套一個(gè)THEN,那么選擇組件如果要選擇這個(gè)THEN應(yīng)該返回什么呢?LiteFlow中規(guī)定,每個(gè)表達(dá)式都可以有一個(gè)id值,你可以設(shè)置id值來設(shè)置一個(gè)表達(dá)式的id值。然后在選擇組件里返回這個(gè)id即可。用法如下:

<chain name="chain1">
    THEN(
        a,
        SWITCH(b).to(
            c, 
            THEN(d, e).id("t1")
        ),
        f
    );
</chain>

如果你想選擇THEN這個(gè)表達(dá)式,那么你可以在選擇節(jié)點(diǎn)里返回t1:

@LiteflowComponent("b")
public class BCmp extends NodeSwitchComponent {
    @Override
    public String processSwitch() throws Exception {
        //do your biz
        return "t1";
    }
}

選擇編排中的tag語(yǔ)法: 事實(shí)上,除了給表達(dá)式賦值id屬性之外,你還可以給表達(dá)式賦值tag屬性。用法如下:

<chain name="chain1">
    THEN(
        a,
        SWITCH(b).to(
            c, 
            THEN(d, e).tag("t1")
        ),
        f
    );
</chain>

如果你想選擇THEN這個(gè)表達(dá)式,那么你可以在選擇節(jié)點(diǎn)里返回:

@LiteflowComponent("b")
public class BCmp extends NodeSwitchComponent {
    @Override
    public String processSwitch() throws Exception {
        return "tag:t1";
        //以下這種也是可以的
        return ":t1";
    }
}

條件編排

條件編排是選擇編排一個(gè)變種,選擇編排是根據(jù)邏輯去選擇多個(gè)子項(xiàng)中的一項(xiàng)。而條件編排只有真和假2個(gè)子項(xiàng),這處理某些業(yè)務(wù)的過程中非常有用。其實(shí)簡(jiǎn)單來說,條件編排就是編程語(yǔ)言中的if else。只不過在LiteFlow EL語(yǔ)法中有一些不一樣的用法。以下IFELIF的第一個(gè)參數(shù)要求定義條件組件。

IF的二元表達(dá)式: 其中x為條件節(jié)點(diǎn),為真的情況下,執(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é)點(diǎn),為真的情況下,執(zhí)行鏈路就為x->a->c,為假鏈路就為x->b->c

<chain name="chain1">
    THEN(
        IF(x, a, b),
        c
    );
</chain>

ELIF表達(dá)式: ELIF關(guān)鍵字的用法其實(shí)和java語(yǔ)言的else if類似,可以跟多個(gè),和IF二元表達(dá)式參數(shù)一樣,一般最后還會(huì)跟個(gè)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這個(gè)鏈路固定循環(huán)了5次。如果你在定義規(guī)則的時(shí)候并不確定要循環(huán)幾次,要在代碼運(yùn)行的時(shí)候才知道。那你也可以這樣定義:

<chain name="chain1">
    FOR(f).DO(THEN(a, b));
</chain>

其中f這個(gè)節(jié)點(diǎn)需要為次數(shù)循環(huán)組件,返回一個(gè)int循環(huán)次數(shù),f節(jié)點(diǎn)的定義,需要繼承NodeForComponent,需要實(shí)現(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)獲取:關(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這個(gè)節(jié)點(diǎn)需要為條件循環(huán)組件,返回一個(gè)布爾值,為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é)點(diǎn)都可以通過this.getLoopIndex()來獲得下標(biāo)。在腳本中通過_meta.loopIndex來獲取。

ITERATOR迭代循環(huán)

<chain name="chain1">
    ITERATOR(x).DO(THEN(a, b));
</chain>

其中x這個(gè)節(jié)點(diǎn)需要為迭代循環(huán)組件,返回一個(gè)迭代器:x節(jié)點(diǎn)的定義,需要繼承NodeIteratorComponent,需要實(shí)現(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語(yǔ)法,代表退出循環(huán)。BREAK關(guān)鍵字可以跟在FORWHILE后面,通常用法為:

<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這個(gè)節(jié)點(diǎn)需要為退出循環(huán)組件,返回一個(gè)布爾值,為true則退出循環(huán)。c節(jié)點(diǎn)的定義,需要繼承NodeBreakComponent,需要實(shí)現(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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 小議Java中@param注解與@see注解的作用

    小議Java中@param注解與@see注解的作用

    這篇文章主要介紹了Java中@param注解與@see注解的作用,注解的功能類似于通常代碼中的注釋,需要的朋友可以參考下
    2015-12-12
  • java操作(DOM、SAX、JDOM、DOM4J)xml方式的四種比較與詳解

    java操作(DOM、SAX、JDOM、DOM4J)xml方式的四種比較與詳解

    java中四種操作(DOM、SAX、JDOM、DOM4J)xml方式的比較與詳解
    2008-10-10
  • 如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪問詳解

    如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪問詳解

    授權(quán)是最常見的JWT使用場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪問的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-02-02
  • Hibernate緩存機(jī)制實(shí)例代碼解析

    Hibernate緩存機(jī)制實(shí)例代碼解析

    這篇文章主要介紹了Hibernate緩存機(jī)制實(shí)例代碼解析,介紹了查詢緩存,一級(jí)二級(jí)緩存等內(nèi)容,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • java?9大性能優(yōu)化經(jīng)驗(yàn)總結(jié)

    java?9大性能優(yōu)化經(jīng)驗(yàn)總結(jié)

    這篇文章主要介紹了java?9大性能優(yōu)化經(jīng)驗(yàn)總結(jié),包括:Java代碼優(yōu)化,數(shù)據(jù)庫(kù)優(yōu)化,分布式緩存,異步化,Web前段,搜索引擎優(yōu)化等需要的朋友可以參考下
    2023-02-02
  • MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解

    MyBatis3源碼解析之如何獲取數(shù)據(jù)源詳解

    用myBatis3與spring整合的時(shí)候,我們可以通過多種方式獲取數(shù)據(jù)源,下面這篇文章主要給大家介紹了關(guān)于MyBatis3源碼解析之如何獲取數(shù)據(jù)源的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • java  HashMap擴(kuò)容詳解及實(shí)例代碼

    java HashMap擴(kuò)容詳解及實(shí)例代碼

    這篇文章主要介紹了java HashMap擴(kuò)容詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java實(shí)現(xiàn)修改圖片文件名的方法示例

    Java實(shí)現(xiàn)修改圖片文件名的方法示例

    在很多應(yīng)用中,用戶需要對(duì)文件進(jìn)行重命名操作,包括圖片文件,圖片文件的重命名操作可以是基于文件內(nèi)容、日期、用戶輸入等,本項(xiàng)目的目標(biāo)是實(shí)現(xiàn)一個(gè)Java程序,能夠修改圖片文件的文件名,并進(jìn)行簡(jiǎn)單的文件名處理,需要的朋友可以參考下
    2025-02-02
  • SpringBoot 整合Jest實(shí)例代碼講解

    SpringBoot 整合Jest實(shí)例代碼講解

    本文通過實(shí)例代碼給大家介紹了SpringBoot 整合Jest的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-08-08
  • Java中的RMI使用方法詳解

    Java中的RMI使用方法詳解

    這篇文章主要介紹了Java中的RMI使用方法,RMI是Java提供的一個(gè)完善的簡(jiǎn)單易用的遠(yuǎn)程方法調(diào)用框架,采用客戶服務(wù)器通信方式,在服務(wù)器上部署了提供各種服務(wù)的遠(yuǎn)程對(duì)象,下面我們來詳細(xì)講解
    2023-10-10

最新評(píng)論