优质博文:IT-BLOG-CN
一、LiteFlow 简介
LiteFlow
是一个轻量且强大的国产规则引擎框架,可用于复杂的组件化业务的编排领域。帮助系统变得更加丝滑且灵活。利用
LiteFlow
,你可以将瀑布流式的代码,转变成以组件为核心概念的代码结构,这种结构的好处是可以任意编排,组件与组件之间是解耦的,组件可以用脚本来定义,组件之间的流转全靠规则来驱动。
LiteFlow
拥有开源规则引擎最为简单的
DSL
语法。 LiteFlow官网
LiteFlow
于
2020
年正式开源,
2021
年获得开源中国年度最受欢迎开源软件殊荣。于
2022
年获得
Gitee
最有价值开源项目
GVP
荣誉。是一个正处在高速发展中的开源项目。
LiteFlow
是一个由社区驱动的项目,拥有一个
2500
多人的使用者社区。虽然相比
Acitiviti
、
Flowable
来说,
LiteFlow
的知名度要低得多,功能也没有这些知名成熟引擎那么强大,但
LiteFlow
还是有诸多优点,能够满足你绝大部分的场景。这些优点包括:
【1】规则多样化: 规则支持
xml
、
json
、
yml
三种规则文件写法方式。
【2】使用便捷: 引几个
jar
包、实现几个接口、写一个流程编排文件,就能运行。
【3】编排丰富: 支持串行、并行、选择、循环、异常处理、嵌套等各种编排方式。
【4】事件监听: 支持事件触发和状态变化监听,可以方便地扩展和定制工作流处理逻辑。
【5】异步超时: 支持异步执行和超时控制,可以提高系统的并发处理能力和稳定性。
【6】支持脚本: 支持各种主流脚本语言。
【7】配置源丰富: 支持将流程定义放到
ZK/DB/Etcd/Nacos/Redis/Apollo
和自定义扩展等。相当于可以实现动态配置更改。
【8】定制化: 高度可定制化,用户可以根据自己的需求自由扩展和定制
LiteFlow
的各种组件和功能。
【9】支持众多脚本语言:
LiteFlow
的脚本组件,支持众多脚本语言
Groovy/JavaScript/QLExpress/Python/Lua/Aviator/Java
,完全和
Java
打通,你可以用脚本来实现任何逻辑。
【10】优雅热刷新机制: 规则变化,无需重启您的应用,即时改变应用的规则。高并发下不会因为刷新规则导致正在执行的规则有任何错乱。
【11】支持广泛: 不管你的项目是不是基于
Springboot
,
Spring
还是任何其他
java
框架构建,
LiteFlow
都能游刃有余。
【12】上下文隔离机制: 可靠的上下文隔离机制,你无需担心高并发情况下的数据串流。
【13】性能卓越: 框架本身几乎不消耗额外性能,性能取决你的组件执行效率。
【14】自带简单监控: 框架内自带一个命令行的监控,能够知道每个组件的运行耗时排行。
适合使用的这项技术的系统
在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统
RPC
调用等等。时间一长,项目几经易手,维护成本就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程,几乎很难实现。
如何打破僵局?
LiteFlow
为解耦逻辑而生,为编排而生,在使用
LiteFlow
之后,你会发现打造一个低耦合,灵活的系统会变得易如反掌!
二、LiteFlow 原理
如果你要对复杂业务逻辑进行新写或者重构,用
LiteFlow
最合适不过。它是一个编排式的规则引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。
LiteFlow
的核心是“流程即代码”,即将业务流程和代码结构紧密耦合在一起。
LiteFlow
采用基于
XML
文件的流程定义方式,通过定义流程节点和连线来描述整个工作流程。每个流程节点都对应着
Java
代码中的一个方法,而连线则对应着方法之间的调用关系。这样一来,我们就可以非常直观地看到整个业务流程的处理过程,而且在修改流程时也更加方便快捷。
组件可实时热更替,也可以给编排好的逻辑流里实时增加一个组件,从而改变你的业务逻辑。
编排语法强大到可以编排出任何你想要的逻辑流程例如:
三、使用场景
**
LiteFlow
适用于哪些场景:**
LiteFlow
适用于拥有复杂逻辑的业务,比如说价格引擎,下单流程等,这些业务往往都拥有很多步骤,这些步骤完全可以按照业务粒度拆分成一个个独立的组件,进行装配复用变更。使用
LiteFlow
,你会得到一个灵活度高,扩展性很强的系统。因为组件之间相互独立,也可以避免改一处而动全身的这样的风险。
**
LiteFlow
不适用于哪些场景:**
LiteFlow
不适合角色任务之间的流转,类似于审批流,A审批完应该是B审批,然后再流转到C角色。这里申明下,
LiteFlow
只做基于逻辑的流转,而不做基于角色任务的流转。如果你想做基于角色任务的流转,推荐使用
flowable
,
activiti
这2个框架。
四、JDK支持情况
LiteFlow
要求的最低的
JDK
版本为
8
,支持
JDK8~JDK17
所有的版本。如果你使用
JDK11
以上,确保
LiteFlow
的版本为
v2.10.6
及其以上版本。因为
LiteFlow
从
v2.10.6
开始,对
JDK11
和
JDK17
进行了详细的用例测试,通过了全部的
900
多个测试用例。而在
v2.10.6
以下版本,在
JDK11
以上是未经过测试用例保障的。特别需要注意的是,如果你使用
JDK11
及其以上的版本,请确保
jvm
参数加上以下参数:
--add-opensjava.base/sun.reflect.annotation=ALL-UNNAMED
五、Springboot 整合流程
LiteFlow
要求的
Springboot
的最低的版本是
2.0
。支持的范围是
Springboot 2.X ~ Springboot 3.X
。如果你使用了最新的
Springboot 3.X
,相应的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
包后,你需要定义并实现一些组件,确保
SpringBoot
会扫描到这些组件并注册进上下文。
@Component("a")publicclassACmpextendsNodeComponent{@Overridepublicvoidprocess(){//do your business}}
以此类推再分别定义b,c组件:
@Component("b")publicclassBCmpextendsNodeComponent{@Overridepublicvoidprocess(){//do your business}}@Component("c")publicclassCCmpextendsNodeComponent{@Overridepublicvoidprocess(){//do your business}}
SpringBoot配置文件
然后,在你的
SpringBoot
的
application.properties
或者
application.yml
里添加配置(这里以
yaml
为例,
properties
也是一样的)
liteflow:#规则文件路径rule-source: config/flow.el.xml
#-----------------以下非必须-----------------#liteflow是否开启,默认为trueenable:true#liteflow的banner打印是否开启,默认为trueprint-banner:true#zkNode的节点,只有使用zk作为配置源的时候才起作用,默认为/lite-flow/flowzk-node: /lite-flow/flow
#上下文的最大数量槽,默认值为1024slot-size:1024#FlowExecutor的execute2Future的线程数,默认为64main-executor-works:64#FlowExecutor的execute2Future的自定义线程池Builder,LiteFlow提供了默认的Buildermain-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder
#自定义请求ID的生成类,LiteFlow提供了默认的生成类request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator
#并行节点的线程池Builder,LiteFlow提供了默认的Builderthread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder
#异步线程最长的等待时间(只用于when),默认值为15000when-max-wait-time:15000#异步线程最长的等待时间(只用于when),默认值为MILLISECONDS,毫秒when-max-wait-time-unit: MILLISECONDS
#when节点全局异步线程池最大线程数,默认为16when-max-workers:16#并行循环子项线程池最大线程数,默认为16parallelLoop-max-workers:16#并行循环子项线程池等待队列数,默认为512parallelLoop-queue-limit:512#并行循环子项的线程池Builder,LiteFlow提供了默认的BuilderparallelLoop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder
#when节点全局异步线程池等待队列数,默认为512when-queue-limit:512#是否在启动的时候就解析规则,默认为trueparse-on-start:true#全局重试次数,默认为0retry-count:0#是否支持不同类型的加载方式混用,默认为falsesupport-multiple-type:false#全局默认节点执行器node-executor-class: com.yomahub.liteflow.flow.executor.DefaultNodeExecutor
#是否打印执行中过程中的日志,默认为trueprint-execution-log:true#是否开启本地文件监听,默认为falseenable-monitor-file:false#简易监控配置选项monitor:#监控是否开启,默认不开启enable-log:false#监控队列存储大小,默认值为200queue-limit:200#监控一开始延迟多少执行,默认值为300000毫秒,也就是5分钟delay:300000#监控日志打印每过多少时间执行一次,默认值为300000毫秒,也就是5分钟period:300000
规则文件的定义
同时,你得在
resources
下的
config/flow.el.xml
中定义规则:
SpringBoot
在启动时会自动装载规则文件。
<?xml version="1.0" encoding="UTF-8"?><flow><chainname="chain1">
THEN(a, b, c);
</chain></flow>
执行
声明启动类:
@SpringBootApplication//把你定义的组件扫入Spring上下文中@ComponentScan({"com.xxx.xxx.cmp"})publicclassLiteflowExampleApplication{publicstaticvoidmain(String[] args){SpringApplication.run(LiteflowExampleApplication.class, args);}}
然后你就可以在
Springboot
任意被
Spring
托管的类中拿到
flowExecutor
,进行执行链路:这个
DefaultContext
是默认的上下文,用户可以用最自己的任意
Bean
当做上下文传入,如果需要传入自己的上下文,则需要传用户
Bean
的
Class
属性
@ComponentpublicclassYourClass{@ResourceprivateFlowExecutor flowExecutor;publicvoidtestConfig(){LiteflowResponse response = flowExecutor.execute2Resp("chain1","arg");}}
六、数据上下文
在执行器执行流程时会分配数据上下文实例给这个请求。不同请求的数据上下文实例是完全隔离的。里面存放着此请求所有的用户数据。不同的组件之间是不传递参数的,所有的数据交互都是通过这个数据上下文来实现的。数据上下文这个概念在
LiteFlow
框架中非常重要,你所有的业务数据都是放在数据上下文中。要做到可编排,一定是消除每个组件差异性的。如果每个组件出参入参都不一致,那就没法编排了。
LiteFlow
对此有独特的设计理念,平时我们写瀑布流的程序时,A调用B,那A一定要把B所需要的参数传递给B,而在
LiteFlow
框架体系中,每个组件的定义中是不需要接受参数的,也无任何返回的。每个组件只需要从数据上下文中获取自己关心的数据即可,而不用关心此数据是由谁提供的,同样的,每个组件也只要把自己执行所产生的结果数据放到数据上下文中即可,也不用关心此数据到底是提供给谁用的。这样一来,就从数据层面一定程度的解耦了。从而达到可编排的目的。关于这个理念,也在
LiteFlow
简介中的设计原则有提到过,给了一个形象的例子,大家可以再去看看。
一旦在数据上下文中放入数据,整个链路中的任一节点都是可以取到的。
默认上下文
LiteFlow
提供了一个默认的数据上下文的实现:
DefaultContext
。这个默认的实现其实里面主要存储数据的容器就是一个
Map
。你可以通过
DefaultContext
中的
setData
方法放入数据,通过
getData
方法获得数据。
::: warning
DefaultContext
虽然可以用,但是在实际业务中,用这个会存在大量的弱类型,存取数据的时候都要进行强转,颇为不方便。所以官方建议你自己去实现自己的数据上下文。
:::
自定义上下文
在一个流程中,总会有一些初始的参数,比如订单号,用户
Id
等等一些的初始参数。这时候需要通过以下方法的第二个参数传入:
//参数为流程ID,无初始流程入参,上下文类型为默认的DefaultContextpublicLiteflowResponseexecute2Resp(String chainId)//第一个参数为流程ID,第二个参数为流程入参。上下文类型为默认的DefaultContextpublicLiteflowResponseexecute2Resp(String chainId,Object param);//第一个参数为流程ID,第二个参数为流程入参,后面可以传入多个上下文classpublicLiteflowResponseexecute2Resp(String chainId,Object param,Class<?>... contextBeanClazzArray)//第一个参数为流程ID,第二个参数为流程入参,后面可以传入多个上下文的BeanpublicLiteflowResponseexecute2Resp(String chainId,Object param,Object... contextBeanArray)
你可以用你自己的任意的
Bean
当做上下文进行传入。
LiteFlow
对上下文的
Bean
没有任何要求。自己定义的上下文实质上就是一个最简单的值对象,自己定义的上下文因为是强类型,更加贴合业务。你可以像这样进行传入:
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始参数,CustomContext.class);
传入之后,
LiteFlow
会在调用时进行初始化,给这个上下文分配唯一的实例。你在组件之中可以这样去获得这个上下文实例:
@LiteflowComponent("yourCmpId")publicclassYourCmpextendsNodeComponent{@Overridepublicvoidprocess(){CustomContext context =this.getContextBean(CustomContext.class);//或者你也可以用这个方法去获取上下文实例,和上面是等价的//CustomContext context = this.getFirstContextBean();...}}
多上下文
LiteFlow
在新版本中支持了多上下文,在执行的时候同时初始化你传入的多个上下文。在组件里也可以根据
class
类型很方便的拿到。你可以像这样进行传入:
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始参数,OrderContext.class,UserContext.class,SignContext.class);
在组件之中可以这样去获得这个上下文实例:
@LiteflowComponent("yourCmpId")publicclassYourCmpextendsNodeComponent{@Overridepublicvoidprocess(){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
版本开始,允许用户传入一个或多个已经初始化好的
bean
作为上下文,而不是传入
class
对象。在拿到
FlowExecutor
之后,你可以像如下一样,传入已经初始化好的
bean
作为上下文(当然也支持多上下文,这里只演示单上下文):
OrderContext orderContext =newOrderContext();
orderContext.setOrderNo("SO11223344");LiteflowResponse response = flowExecutor.execute2Resp("chain1",null, orderContext);
::: warning
框架并不支持上下文
bean
和
class
混传,你要么都传
bean
,要么都传
class
。
:::
七、异步Future
publicFuture<LiteflowResponse>execute2Future(String chainId,Object param,Class<?>... contextBeanClazzArray)
如果调用这个方法,那就是无阻塞的,想要拿到
response
,请用得到的
future.get()
就可以了。同时,主执行器在这个模式下的线程数和线程池也可以自定义,具体配置如下,
LiteFlow
已经设置了预设值,你也可自己定义。
liteflow.main-executor-works=64
liteflow.main-executor-class=com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder
如果你定义了自定义线程池,你需新建一个类,然后实现
ExecutorBuilder
接口:
publicclassCustomThreadBuilderimplementsExecutorBuilder{@OverridepublicExecutorServicebuildExecutor(){returnExecutors.newCachedThreadPool();}}
八、规则写法
串行编排
如果你要依次执行
a,b,c,d
四个组件,你可以用THEN关键字,需要注意的是,
THEN
必须大写。
<chainname="chain1">
THEN(a, b, c, d);
</chain>
并行编排
如果你要并行执行
a,b,c
三个组件,你可以用
WHEN
关键字,需要注意的是,
WHEN
必须大写。
<chainname="chain1">
WHEN(a, b, c);
</chain>
和串行嵌套起来:让我们把THEN和WHEN结合起来用,看一个示例:
b,c,d
默认并行都执行完毕后,才会执行
e
。
<chainname="chain1">
THEN(
a,
WHEN(b, c, d),
e
);
</chain>
上面的示例应该很好理解吧,那么再看一个示例:
<chainname="chain1">
THEN(
a,
WHEN(b, THEN(c, d)),
e
);
</chain>
忽略错误:
WHEN
关键字提供了一个子关键字
ignoreError
(默认为`false``)来提供忽略错误的特性,用法如下:
<chainname="chain1">
THEN(
a,
WHEN(b, c, d).ignoreError(true),
e
);
</chain>
设
b,c,d
中任一一个节点有异常,那么最终
e
仍旧会被执行。
任一节点先执行完则忽略其他:
WHEN
关键字提供了一个子关键字
any
(默认为
false
)用来提供并行流程中,任一条分支先执行完即忽略其他分支,继续执行的特性。用法如下:假设
e
节点先执行完,那么不管其他分支是否执行完,会立马执行节点
f
。
<chainname="chain1">
THEN(
a,
WHEN(b, THEN(c, d), e).any(true),
f
);
</chain>
指定任意节点先执行完则忽略其他:
LiteFlow
从
v2.11.1
开始,支持了并行编排中指定节点的执行则忽略其他,
WHEN
关键字新增子关键字
must
(不可为空),可用于指定需等待执行的任意节点,可以为
1
个或者多个,若指定的所有节点率先完成,则继续往下执行,忽略同级别的其他任务,用法如下:
must
指定了
b,c
,则
b,c
是一定会被执行完毕了,如果
b,c
执行完毕了后
d
还未执行完,则忽略,直接执行下一个组件
f
。
<chainname="chain1">
THEN(
a,
WHEN(b, c, d).must(b, c),
f
);
</chain>
以上是单节点的用法,
must
还可以指定一个或多个表达式。比如:
WHEN
里有一个嵌套的
THEN
,如果需要指定这个表达式,则需要给这个表达式设置一个
id
,
must
里需要指定这个
id
,需要注意的是,
must
里指定
id
,需要用引号括起来。
<chainname="chain1">
THEN(
a,
WHEN(b, THEN(c, d).id("t1"), e).must(b, "t1"),
f
);
</chain>
开启WHEN线程池隔离:
目前
liteflow
设计里
when
线程池,如果你不单独设置自定义线程池,那么就会用默认的线程池。而这个线程池,是所有的
when
共同一个。
LiteFlow从2.11.1
开始,提供一个
liteflow.when-thread-pool-isolate
参数,默认为
false
,如果设为
true
,则会开启
WHEN
的线程池隔离机制,这意味着每一个
when
都会有单独的线程池。这个特性对于运行复杂的嵌套
when
时是可以提升运行速度的且规避掉一些锁的问题。
你可以如下配置来开启:
liteflow.when-thread-pool-isolate=true
选择编排
我们在写业务逻辑的时候,通常会碰到选择性问题,即,如果返回结果1,则进入
A
流程,如果返回结果2,则进入
B
流程,如果返回结果3,则进入
C
流程。在有些流程定义中也被定义为排他网关。这个通过
LiteFLow
的表达式也非常容易实现,你可以用
SWITCH...TO
的组合关键字,注意的是
SWITCH
必须大写,
to
大小写均可。
如果,根据组件
a
,来选择执行
b,c,d
中的一个,你可以如下声明:
@LiteflowComponent("a")publicclassACmpextendsNodeSwitchComponent{@OverridepublicStringprocessSwitch()throwsException{System.out.println("Acomp executed!");return"c";}}
DEFAULT关键字:
LiteFlow
从
2.9.5
开始,对选择编排新增了一个
DEFAULT
关键字。用法为
SWITCH...TO...DEFAULT
。比如如下表达式:
<chainname="chain1">
SWITCH(x).TO(a, b, c).DEFAULT(y);
</chain>
如上表达式的
x
如果返回非
a,b,c
中的一个,则默认选择到
y
。当然
DEFAULT
里面也可以是一个表达式。
**选择编排中的
id
语法:** 接下来展示一个
SWITCH
中套
THEN
和
WHEN
的例子。如果你阅读过选择组件这一章,就应该知道,
LiteFlow
通过选择组件的返回来确定该选择什么。那么如果
SWITCH
中套一个
THEN
,那么选择组件如果要选择这个
THEN
应该返回什么呢?
LiteFlow
中规定,每个表达式都可以有一个
id
值,你可以设置id值来设置一个表达式的
id
值。然后在选择组件里返回这个
id
即可。用法如下:
<chainname="chain1">
THEN(
a,
SWITCH(b).to(
c,
THEN(d, e).id("t1")
),
f
);
</chain>
如果你想选择
THEN
这个表达式,那么你可以在选择节点里返回
t1
:
@LiteflowComponent("b")publicclassBCmpextendsNodeSwitchComponent{@OverridepublicStringprocessSwitch()throwsException{//do your bizreturn"t1";}}
选择编排中的tag语法: 事实上,除了给表达式赋值
id
属性之外,你还可以给表达式赋值
tag
属性。用法如下:
<chainname="chain1">
THEN(
a,
SWITCH(b).to(
c,
THEN(d, e).tag("t1")
),
f
);
</chain>
如果你想选择
THEN
这个表达式,那么你可以在选择节点里返回:
@LiteflowComponent("b")publicclassBCmpextendsNodeSwitchComponent{@OverridepublicStringprocessSwitch()throwsException{return"tag:t1";//以下这种也是可以的return":t1";}}
条件编排
条件编排是选择编排一个变种,选择编排是根据逻辑去选择多个子项中的一项。而条件编排只有真和假2个子项,这处理某些业务的过程中非常有用。其实简单来说,条件编排就是编程语言中的
if else
。只不过在
LiteFlow EL
语法中有一些不一样的用法。以下
IF
和
ELIF
的第一个参数要求定义条件组件。
IF的二元表达式: 其中
x
为条件节点,为真的情况下,执行链路就为
x->a->b
,为假链路就为
x->b
。
<chainname="chain1">
THEN(
IF(x, a),
b
);
</chain>
@Component("x")publicclassXCmpextendsNodeIfComponent{@OverridepublicbooleanprocessIf()throwsException{//do your bizreturntrue;}}
IF的三元表达式: 其中
x
为条件节点,为真的情况下,执行链路就为
x->a->c
,为假链路就为
x->b->c
。
<chainname="chain1">
THEN(
IF(x, a, b),
c
);
</chain>
ELIF表达式:
ELIF
关键字的用法其实和
java
语言的
else if
类似,可以跟多个,和
IF
二元表达式参数一样,一般最后还会跟个
ELSE
,用于多重条件的判断:
<chainname="chain1">
IF(x1, a).ELIF(x2, b).ELIF(x3, c).ELIF(x4, d).ELSE(THEN(m, n));
</chain>
循环编排
FOR循环:
FOR
循环表达式用于固定次数的循环,通常的用法为:
<chainname="chain1">
FOR(5).DO(THEN(a, b));
</chain>
上述表达式表示把
a->b
这个链路固定循环了
5
次。如果你在定义规则的时候并不确定要循环几次,要在代码运行的时候才知道。那你也可以这样定义:
<chainname="chain1">
FOR(f).DO(THEN(a, b));
</chain>
其中
f
这个节点需要为次数循环组件,返回一个
int
循环次数,
f
节点的定义,需要继承
NodeForComponent
,需要实现
processFor
方法:
@LiteflowComponent("f")publicclassFCmpextendsNodeForComponent{@OverridepublicintprocessFor()throwsException{//这里根据业务去返回for的结果}}
循环下标获取:关键字
FOR...DO...
中
DO
里面的任意
java
组件都可以通过
this.getLoopIndex()
来获得下标。在脚本中通过
_meta.loopIndex
来获取。
WHILE循环:
<chainname="chain1">
WHILE(w).DO(THEN(a, b));
</chain>
其中
w
这个节点需要为条件循环组件,返回一个布尔值,为
true
则继续循环
@LiteflowComponent("w")publicclassWCmpextendsNodeWhileComponent{@OverridepublicbooleanprocessWhile()throwsException{//这里根据业务去返回while的结果}}
循环下标获取:关键字
WHILE...DO...
中
DO
里面的任意节点都可以通过
this.getLoopIndex()
来获得下标。在脚本中通过
_meta.loopIndex
来获取。
ITERATOR迭代循环
<chainname="chain1">
ITERATOR(x).DO(THEN(a, b));
</chain>
其中
x
这个节点需要为迭代循环组件,返回一个迭代器:
x
节点的定义,需要继承
NodeIteratorComponent
,需要实现
processIterator
方法:
@LiteflowComponent("x")publicclassXCmpextendsNodeIteratorComponent{@OverridepublicIterator<?>processIterator()throwsException{List<String> list =ListUtil.toList("jack","mary","tom");return list.iterator();}}
BREAK
LiteFlow
同样也支持
BREAK
语法,代表退出循环。
BREAK
关键字可以跟在
FOR
和
WHILE
后面,通常用法为:
<chainname="chain1">
FOR(f).DO(THEN(a, b)).BREAK(c);
</chain><chainname="chain1">
WHILE(w).DO(THEN(a, b)).BREAK(c);
</chain>
其中
c
这个节点需要为退出循环组件,返回一个布尔值,为
true
则退出循环。
c
节点的定义,需要继承
NodeBreakComponent
,需要实现
processBreak
方法:
@LiteflowComponent("c")publicclassCCmpextendsNodeBreakComponent{@OverridepublicbooleanprocessBreak()throwsException{//这里根据业务去返回break的结果}}
BREAK
关键字是在每次循环的末尾进行判断的。
版权归原作者 程序猿进阶 所有, 如有侵权,请联系我们删除。