LiteFlow

月伴飞鱼 2025-01-18 20:11:10
框架相关
支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者!

LiteFlow是一个编排式的规则引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。

官方网址:https://liteflow.yomahub.com

img

IDAE插件

LiteFlow 拥有自己的IDEA插件LiteFlowX

通过该插件能支持规则文件的智能提示、语法高亮、组件与规则文件之间的跳转及LiteFlow工具箱等功能。

规则表达式

串行编排:

当想要依次执行a、b、c、d四个组件时,直接使用THEN关键字即可。

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

并行编排:

如果想并行执行a、b、c三个组件的话,可以使用WHEN关键字。

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

选择编排:

如果想实现代码中的switch逻辑的话,例如通过a组件的返回结果进行判断。

如果返回的是组件名称b的话则执行b组件,可以使用SWITCH关键字。

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

条件编排:

如果想实现代码中的if逻辑的话,例如当x组件返回为true时执行a,可以使用IF关键字。

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

如果想实现if的三元运算符逻辑的话,例如x组件返回为true时执行a组件,返回为false时执行b组件。

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

如果想实现if else逻辑的话,可以使用ELSE关键字,和上面实现效果等价。

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

如果想实现else if逻辑的话,可以使用ELIF关键字。

<chain name="chain1">
    IF(x1, a).ELIF(x2, b).ELSE(c);
</chain>

使用子流程:

当某些流程比较复杂时,可以定义子流程,然后在主流程中引用,这样逻辑会比较清晰。

例如我们有如下子流程,执行C、D组件。

<chain name="subChain">
   THEN(C, D);
</chain>

然后我们直接在主流程中引用子流程即可。

<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 类型参数,一般情况下是在第一个节点中,将传入参数设置到上下文对象中。

# 执行流程时,需要传递el文件,初始化参数以及上下文对象,这里的上下文可以设置多个
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 流程初始参数, CustomContext.class);

业务实践

使用电商场景的应用,订单完成后,进行积分的发放,消息发送,同时并行发送短信和邮件。

<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="test_flow">
        THEN(
           prepareTrade, grantScore, sendMq, WHEN(sendEmail, sendPhone)
        );
    </chain>
</flow>

在订单完成之后异步执行,传递参数并执行相应的规则流程。

// 处理 交易完成后任务,异步执行
@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));
}

在正式处理业务流程之前,需要先进行数据的预处理,将流程入参转转换成上下文对象,方便参数的传递和设置。

// 数据准备和校验处理
@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));
        // 停止任务
        // setIsEnd(Boolean.TRUE);
        AppFlowContext context = this.getContextBean(AppFlowContext.class);
        log.info("设置上下文对象{}",JSONObject.toJSONString(context));
}

在具体的业务处理环节,以积分发放为例,可以获取上下文对象进行业务操作。

同时也可以重写 isAccess 方法,来判断是否处理该节点。

具体的业务流程都可以抽象成一个 node 节点,存放在 test_flow.el.xml 中进行执行。

@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;
    }
}
支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者!