# 借助流程引擎降低系统的复杂度!

作者:Tom哥
公众号:微观技术
博客:https://offercome.cn (opens new window)
人生理念:知道的越多,不知道的越多,努力去学

作为软件架构师,当面对复杂的业务逻辑,我们常用的解决方案就是拆分

  1. 将一个大的业务域拆分为若干子域
  2. 将相似业务逻辑抽象成若干组件,并结合 23 种软件设计模式,提升系统扩展性

以流量网关为例:

我们会定义 Filter 接口,子类通过实现 filter() 方法来满足自己的业务逻辑,如:限流逻辑鉴权逻辑 等,如果某些业务流程不需要执行该 Filter 组件,我们可以在 isSkip 方法里定义跳出逻辑,直接跳过该组件,继续执行下一个组件。

最后我们定义了这么多的 Filter 组件,通过 Spring 框架扫描优先级注解,完成了组件链的串联。

当然这个编排比较单一,不够灵活。无法实现一些串行并行 的自由组合。

比如,我们面对上图这样的业务流程该如何应对?是自己借助 JUC 并发包以及各种 if else 定制化实现流程控制吗?

另外,随着业务后续迭代,这些任务间的关系还会发生变化,每次都去改动代码,违反软件的开闭原则 ,很容易发生线上故障。

**🚀 给大家推荐一款轻量级的流程引擎 **

# LiteFlow

LiteFlow 是一款国产开源的,具有轻量,快速,稳定可编排的组件式规则引擎,帮助我们拆解实现各种复杂的业务逻辑,开箱即用,上手容易。

# 主要特性

  1. 组件定义统一: 所有的逻辑都是组件,为所有的逻辑提供统一化的组件实现方式,小身材,大能量。
  2. 规则轻量: 基于规则文件来编排流程,学习规则入门只需要5分钟,一看既懂。
  3. 规则多样化: 规则支持xml、json、yml三种规则文件写法方式,喜欢哪种用哪个。
  4. 任意编排: 同步异步混编,再复杂的逻辑过程,利用LiteFlow的规则,都是很容易做到的,看规则文件就能知道逻辑是如何运转的。
  5. 规则能从任意地方加载: 框架中提供本地文件配置源和zk配置源的实现,也提供了扩展接口,您可以把规则存储在任何地方。
  6. 优雅热刷新机制: 规则变化,无需重启您的应用,即时改变应用的规则。高并发下不会因为刷新规则导致正在执行的规则有任何错乱。
  7. 支持广泛: 不管你的项目是不是基于Springboot,Spring还是任何其他java框架构建,LiteFlow都能游刃有余。
  8. JDK支持: 从JDK8到JDK17,统统支持。无需担心JDK版本。
  9. 脚本语言支持: 可以定义脚本语言节点,支持QLExpress和Groovy两种脚本。未来还会支持更多的脚本语言。
  10. 规则嵌套支持: 只要你想的出,你可以利用简单的表达式完成多重嵌套的复杂逻辑编排。
  11. 组件重试支持: 组件可以支持重试,每个组件均可自定义重试配置和指定异常。
  12. 上下文隔离机制: 可靠的上下文隔离机制,你无需担心高并发情况下的数据串流。
  13. 声明式组件支持: 你可以让你的任意类秒变组件。
  14. 详细的步骤信息: 你的链路如何执行的,每个组件耗时多少,报了什么错,一目了然。
  15. 稳定可靠: 历时2年多的迭代,在各大公司的核心系统上稳定运行。
  16. 性能卓越: 框架本身几乎不消耗额外性能,性能取决你的组件执行效率。
  17. 自带简单监控: 框架内自带一个命令行的监控,能够知道每个组件的运行耗时排行。

LiteFlow 设计了非常强大的规则表达式,一切复杂的流程在 LiteFlow 表达式的加持下,都异常丝滑简便。

我们来一起看下 EL 规则的写法

# LiteFlow 规则语法

# 1、串行编排

依次执行 a、b、c、d四个组件,用 THEN 关键字

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

# 2、并行编排

并行执行a、b、c三个组件,用WHEN 关键字

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

# 3、选择编排

根据组件 a 的运行结果,选择执行 b、c、d 中的一个,用 SWITCH 关键字

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

# 4、条件编排

条件编排就是变成语言中的 if else,使用 IF 关键字

其中 x 为条件节点,为真的情况下,执行链路就为x->a->c,为假链路就为x->b->c

<chain name="chain1">
 THEN(
 IF(x, a, b),
 c
 );
</chain>
1
2
3
4
5
6

比如,我们要实现这样一个复杂的流程

对应的 EL 表达式为:

<chain name="chain1">
 IF(x1, a).ELIF(x2, b).ELIF(x3, c).ELIF(x4, d).ELSE(THEN(m, n));
</chain>
1
2
3

# 5、子流程

当遇到一些复杂的业务,表达式嵌套多层,很不直观,我们可以先定义子流程,然后在主流程中引用。这样逻辑会比较清晰

定义子流程 sub_chain ,串行执行 a、b 两个组件

<chain name="sub_chain">
 	THEN(a,b);
</chain>
1
2
3

然后,在主流程中引入之前定义的子流程 sub_chain

<chain name="mainChain">
 WHEN(
 	sub_chain,
 c,d
 );
</chain>
1
2
3
4
5
6

# 实战案例

# 1、需求描述

看完介绍是不是很手痒,接下来我们就以一个电商的 订单价格计算 为例子,讲解下 LiteFlow 如何使用

首先,我们看下订单价格计算接口 都涉及哪些业务逻辑,为了快速切入,画了个流程图便于大家理解

毕竟,一图胜千言哈

# 2、项目代码实现

以 Spring Boot 应用为例,首先在 pom.xml 文件添加下面的依赖

修改 application.yml 配置文件,添加 LiteFlow 的规则文件路径

定义组件,继承 NodeComponent 类 ,并重写 process() 方法,里面实现自己负责的业务逻辑,比如:促销满减计算、会员折扣计算、运费计算等

通过重写 isAccess() 方法来决定是否执行该组件

MemberDiscountCmp 负责会员折扣计算,根据 memberCode 查询会员等级,并获取对应的会员折扣,然后计算订单可以减免多少优惠

PostageCondCmp 组件比较特殊,根据 是否境外购 选择对应的运费计算组件,继承了 NodeSwitchComponent ,并实现了 processSwitch() 方法

其他业务组件 基本类似,就不一一介绍了,感兴趣的同学可以自己看下代码

所有组件实例无缝支持 Spring 框架,通过@Component注解标识,所有的Bean实例全部交由 Spring 容器统一管理

定义好组件后,接下来就要编写 EL 规则表达式,将所有的流程关联起来

最后,启动 Spring Boot 工程,访问地址:http://localhost:8580/

# 代码地址

https://gitee.com/aalansehaiyang/liteflow-example

上次更新: 2023/3/7