LiteFlow实现业务流程编排!
发表于更新于
框架框架LiteFlow实现业务流程编排!
月伴飞鱼
LiteFlow是一个编排式的规则引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。
官方网址:https://liteflow.yomahub.com

IDAE插件
LiteFlow 拥有自己的IDEA插件LiteFlowX。
通过该插件能支持规则文件的智能提示、语法高亮、组件与规则文件之间的跳转及LiteFlow工具箱等功能。
规则表达式
串行编排:
当想要依次执行a、b、c、d四个组件时,直接使用THEN关键字即可。
1 2 3
| <chain name="chain1"> THEN(a, b, c, d); </chain>
|
并行编排:
如果想并行执行a、b、c三个组件的话,可以使用WHEN关键字。
1 2 3
| <chain name="chain1"> WHEN(a, b, c); </chain>
|
选择编排:
如果想实现代码中的switch逻辑的话,例如通过a组件的返回结果进行判断。
如果返回的是组件名称b的话则执行b组件,可以使用SWITCH关键字。
1 2 3
| <chain name="chain1"> SWITCH(a).to(b, c, d); </chain>
|
条件编排:
如果想实现代码中的if逻辑的话,例如当x组件返回为true时执行a,可以使用IF关键字。
1 2 3
| <chain name="chain1"> IF(x, a); </chain>
|
如果想实现if的三元运算符逻辑的话,例如x组件返回为true时执行a组件,返回为false时执行b组件。
1 2 3
| <chain name="chain1"> IF(x, a, b); </chain>
|
如果想实现if else逻辑的话,可以使用ELSE关键字,和上面实现效果等价。
1 2 3
| <chain name="chain1"> IF(x, a).ELSE(b); </chain>
|
如果想实现else if逻辑的话,可以使用ELIF关键字。
1 2 3
| <chain name="chain1"> IF(x1, a).ELIF(x2, b).ELSE(c); </chain>
|
使用子流程:
当某些流程比较复杂时,可以定义子流程,然后在主流程中引用,这样逻辑会比较清晰。
例如我们有如下子流程,执行C、D组件。
1 2 3
| <chain name="subChain"> THEN(C, D); </chain>
|
然后我们直接在主流程中引用子流程即可。
1 2 3 4 5 6 7
| <chain name="mainChain"> THEN( A, B, subChain, E ); </chain>
|
相关组件
普通组件需要继承NodeComponent并实现process()方法,还需设置@Component注解的名称。
- 可以通过重写
isAccess方法来决定是否执行该组件。
LiteFlow 的组件在规则文件中即对应的节点:
普通组件
普通组件需要集成的是 NodeComponent, 可以用在 when 和 then 逻辑中,具体的业务需要在 process 中去执行。
同时在 node 节点中,可以覆盖 isAccess 方法,表示是否进入该节点执行业务逻辑。
isContinueOnError 判断在出错的情况下是否继续执行下一个组件,默认为 false。
isEnd 方法表示是否终止流程,默认为true。
选择组件
选择组件是通过业务逻辑来判断接下来的动作要执行哪一个节点,类似于 Java中的 switch 。
在代码中则需要继承 NodeSwitchComponent 实现 processWitch 方法来处理业务。
条件组件
条件组件称之为 if 组件,返回的结果是 true 或者 false,代码需要集成 NodeIfComponent 重写 processIf 方法。
数据上下文
LiteFlow上下文对象起到参数传递的作用,因为不同业务需要的输入输出参数是不同的。
上下文传入的是一个 class 类型参数,一般情况下是在第一个节点中,将传入参数设置到上下文对象中。
1 2
| # 执行流程时,需要传递el文件,初始化参数以及上下文对象,这里的上下文可以设置多个 LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始参数, CustomContext.class);
|
业务实践
使用电商场景的应用,订单完成后,进行积分的发放,消息发送,同时并行发送短信和邮件。
1 2 3 4 5 6 7 8
| <?xml version="1.0" encoding="UTF-8"?> <flow> <chain name="test_flow"> THEN( prepareTrade, grantScore, sendMq, WHEN(sendEmail, sendPhone) ); </chain> </flow>
|
在订单完成之后异步执行,传递参数并执行相应的规则流程。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Async(value = "getAsyncExecutor") public void handleApp(AppFlowDto flowDto){ LiteflowResponse response = flowExecutor.execute2Resp("test_flow", flowDto, AppFLowContext.class); if (!response.isSuccess()) { Exception e = response.getCause(); Log.warn(" error is {}", e.getCause(),e); } AppFlowContext context = response.getContextBean(AppFlowContext.class); log.info("handleApp 执行完成后 context {}",JSONObject.toJSONString(context)); }
|
在正式处理业务流程之前,需要先进行数据的预处理,将流程入参转转换成上下文对象,方便参数的传递和设置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Slf4j @Component(valve = "prepareTrade") public class PrepareTrade extends NodeComponent { @Override public void process() throws Exception { log.info("交易完成后业务处理数据准备和校验"); AppFlowDto req = this.getslot().getRequestData(); log.info("请求参数 {}",JSONObject.toJSONString(req)); AppFlowContext context = this.getContextBean(AppFlowContext.class); log.info("设置上下文对象{}",JSONObject.toJSONString(context)); }
|
在具体的业务处理环节,以积分发放为例,可以获取上下文对象进行业务操作。
同时也可以重写 isAccess 方法,来判断是否处理该节点。
具体的业务流程都可以抽象成一个 node 节点,存放在 test_flow.el.xml 中进行执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Slf4j @Component(value="grantScore") public class GrantScore extends NodeComponent { @Override public void process() throws Exception { AppFlowContext context = this.getContextBean(AppFlowContext.class); log.info("business cxt {}",JSONObject.toJSONString(context)); TimeUnit.SECONDS.sleep(RandomUtil.randomInt(0,20)); } @Override public boolean isAccess() throws Exception { AppFlowContext context = this.getContextBean(AppFlowContext.class); log.info("判断是否处理该节点 cxt {}",JSONObject.toJSONString(context)); return Boolean.TRUE; } }
|