Liteflow 一个解耦/组件化复杂业务流程的工具

2,709 阅读6分钟

以下介绍直接引用官网,写得非常易懂,地址:yomahub.com/liteflow/do…

官网介绍

前言

在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护的成本得就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程,几乎很难实现。

LiteFlow框架的作用

LiteFlow就是为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件,并支持热加载规则配置,实现即时修改。

使用LiteFlow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。这样,所有的组件,就能按照你的规则配置去进行复杂的流转。

LiteFlow的设计原则

LiteFlow是基于工作台模式进行设计的,何谓工作台模式?

n个工人按照一定顺序围着一张工作台,按顺序各自生产零件,生产的零件最终能组装成一个机器,每个工人只需要完成自己手中零件的生产,而无需知道其他工人生产的内容。每一个工人生产所需要的资源都从工作台上拿取,如果工作台上有生产所必须的资源,则就进行生产,若是没有,就等到有这个资源。每个工人所做好的零件,也都放在工作台上。

这个模式有几个好处:

  • 每个工人无需和其他工人进行沟通。工人只需要关心自己的工作内容和工作台上的资源。这样就做到了每个工人之间的解耦和无差异性。
  • 即便是工人之间调换位置,工人的工作内容和关心的资源没有任何变化。这样就保证了每个工人的稳定性。
  • 如果是指派某个工人去其他的工作台,工人的工作内容和需要的资源依旧没有任何变化,这样就做到了工人的可复用性。
  • 因为每个工人不需要和其他工人沟通,所以可以在生产任务进行时进行实时工位更改:替换,插入,撤掉一些工人,这样生产任务也能实时的被更改。这样就保证了整个生产任务的灵活性。

这个模式映射到LiteFlow框架里,工人就是组件,工人坐的顺序就是流程配置,工作台就是上下文,资源就是参数,最终组装的这个机器就是这个业务。正因为有这些特性,所以LiteFlow能做到统一解耦的组件和灵活的装配。

实际场景

场景1

我们在做在线教育系统的时候的下单流程,有两种下单方式,一是直接对老师下单买这个老师的课时,一个是先买课时,再分配老师。其实最终下的订单都是一样的,只是有没有分配老师,然而又穿插的不一样的业务流程,具体:

下单流程1:对老师下单

1. 获取教师详情
2. 获取课时详情
3. 检测教师是否有空余排课时间
4. 检测课时库存
5. 创建订单流程-将老师信息填入订单表
6. 创建订单流程-将课时信息填入订单表
7. 支付
8. 更新老师排课时间
9. 发送消息通知老师
下单流程2:对课时下单
1. 获取课时详情
2. 检测课时库存
3. 创建订单流程-将课时信息填入订单表
4. 支付
5. 发送消息通知教管安排老师

大家可以看到,虽然是同种下单,但是流程是不一样的,并且有些步骤的可以独立出来解耦的,我们平时开发的时候遇到这样的需求一般都是写2个又长又臭的代码方法,而这些代码又是耦合在一起,维护性太差,目前为止可能还看不到Liteflow的强大之处,如果接下来又有一个需求:如果是管理员在后台系统下单无需检测库存;难道我们又要写第三个又长又臭的代码出来吗?

使用Liteflow就可以把各步骤组件化进行装配的优势就很明显了:

下单流程3:对课时下单 && 不检测库存
1. 获取课时详情
2. 创建订单流程-将课时信息填入订单表
3. 支付
4. 发送消息通知教管安排老师

我只需把检测库存的组件编排走就可以了,代码完全可以复用。想必大家已经明白Liteflow的用途了

简单实例

PS:此处例子只是用来简单演示,Liteflow功能远不止如此,具体去官网的文档和示例工程更全面

  1. 我们先定义一个数据插槽
/**
 * 定义一个插槽 (用简单的String演示)
 * @author yejunxi
 * @date 2021/8/28
 */
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@Data
public class OrderSlot extends AbsSlot {

    /**
     * 课时详情
     */
    private String courseInfo;

    /**
     * 教师详情
     */
    private String teacherInfo;

    /**
     * 库存
     */
    private Integer stock;

}
  1. 定义4个组件:获取老师请求、获取课程详情、检测库存、下单
/**
 * 下单组件-补充订单教师详情
 *
 * @author yejunxi
 * @date 2021/8/28
 */
@LiteflowComponent("OrderTeacherCmp")
public class OrderTeacherCmp extends NodeComponent {
    @Override
    public void process() throws Exception {
        OrderSlot orderSlot = this.getSlot();
        orderSlot.setTeacherInfo("教师详情");

        System.out.println("获取教师信息");
    }
}

/**
 * 下单组件-补充订单课时详情
 *
 * @author yejunxi
 * @date 2021/8/28
 */
@LiteflowComponent("OrderCourseCmp")
public class OrderCourseCmp extends NodeComponent {
    @Override
    public void process() throws Exception {
        OrderSlot orderSlot = this.getSlot();
        orderSlot.setCourseInfo("课时详情");
        orderSlot.setStock(1);

        System.out.println("获取课时信息");
    }
}

/**
 * 下单组件-检测课时库存
 *
 * @author yejunxi
 * @date 2021/8/28
 */
@LiteflowComponent("CheckCourseStockCmp")
public class CheckCourseStockCmp extends NodeComponent {
    @Override
    public void process() throws Exception {
        OrderSlot orderSlot = this.getSlot();
        String courseInfo = orderSlot.getCourseInfo();
    }


    /**
     * 表示出错是否继续往下执行下一个组件,默认为false
     *
     * @return
     */
    @Override
    public boolean isEnd() {
        System.out.println("检测库存");
        //判断库存是否充足
        OrderSlot orderSlot = this.getSlot();
        return orderSlot.getStock() <= 0;
    }
}
/**
 * 下单组件-创建订单
 *
 * @author yejunxi
 * @date 2021/8/28
 */
@LiteflowComponent("OrderCreateCmp")
public class OrderCreateCmp extends NodeComponent {
    @Override
    public void process() throws Exception {
        OrderSlot orderSlot = this.getSlot();
        System.out.println("此处已经拿到完整的slot进行下单:" + orderSlot.toString());
    }
}
  1. 定义组件装配
<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <!--    下单检测库存-->
    <chain name="createOrder">
        <!--读取老师、课程信息-->
        <then value="OrderTeacherCmp,OrderCourseCmp"/>
        <!--检测库存-->
        <then value="CheckCourseStockCmp"/>
        <!--下单-->
        <then value="OrderCreateCmp"/>
    </chain>


    <!--    下单-不检测库存-->
    <chain name="createOrderNotCheckStock">
        <!--读取老师、课程信息-->
        <then value="OrderTeacherCmp,OrderCourseCmp"/>
        <!--下单-->
        <then value="OrderCreateCmp"/>
    </chain>

</flow>
  1. 调用
String courseId = "课程ID";
//检测库存下单
LiteflowResponse<OrderSlot> response1 = flowExecutor.execute2Resp("createOrder", courseId, OrderSlot.class);
//不检测库存下单
LiteflowResponse<OrderSlot> response2= flowExecutor.execute2Resp("createOrderNotCheckStock", courseId, OrderSlot.class);