规则引擎LiteFlow
规则引擎LiteFlow
1.简介
官网:https://liteflow.cc/pages/5816c5/
在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。时间一长,项目几经易手,维护成本就会越来越高。各种硬代码判断,分支条件越来越多。代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更业务流程,几乎很难实现。
如何打破僵局?LiteFlow为解耦逻辑而生,为编排而生,在使用LiteFlow之后,你会发现打造一个低耦合,灵活的系统会变得易如反掌!
LiteFlow是一个非常强大的现代化的规则引擎框架,融合了编排特性和规则引擎的所有特性。
2.依赖
LiteFlow要求的Springboot的最低的版本是2.0。
支持的范围是Springboot 2.X ~ Springboot 3.X。
当然如果你使用了最新的Springboot 3.X,相应的JDK版本也要切换为JDK17。
示例:版本号可以改动
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.10.6</version>
</dependency>
3.配置项
liteflow:
#规则文件路径
rule-source: config/flow.el.xml
#-----------------以下非必须-----------------
#liteflow是否开启,默认为true
enable: true
#liteflow的banner打印是否开启,默认为true
print-banner: true
#zkNode的节点,只有使用zk作为配置源的时候才起作用,默认为/lite-flow/flow
zk-node: /lite-flow/flow
#上下文的最大数量槽,默认值为1024
slot-size: 1024
#FlowExecutor的execute2Future的线程数,默认为64
main-executor-works: 64
#FlowExecutor的execute2Future的自定义线程池Builder,LiteFlow提供了默认的Builder
main-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder
#自定义请求ID的生成类,LiteFlow提供了默认的生成类
request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator
#并行节点的线程池Builder,LiteFlow提供了默认的Builder
thread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder
#异步线程最长的等待时间(只用于when),默认值为15000
when-max-wait-time: 15000
#异步线程最长的等待时间(只用于when),默认值为MILLISECONDS,毫秒
when-max-wait-time-unit: MILLISECONDS
#when节点全局异步线程池最大线程数,默认为16
when-max-workers: 16
#并行循环子项线程池最大线程数,默认为16
parallel-max-workers: 16
#并行循环子项线程池等待队列数,默认为512
parallel-queue-limit: 512
#并行循环子项的线程池Builder,LiteFlow提供了默认的Builder
parallel-loop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder
#when节点全局异步线程池等待队列数,默认为512
when-queue-limit: 512
#设置解析模式,一共有三种模式,PARSE_ALL_ON_START | PARSE_ALL_ON_FIRST_EXEC | PARSE_ONE_ON_FIRST_EXEC
parse-mode: PARSE_ALL_ON_START
#全局重试次数,默认为0
retry-count: 0
#是否支持不同类型的加载方式混用,默认为false
support-multiple-type: false
#全局默认节点执行器
node-executor-class: com.yomahub.liteflow.flow.executor.DefaultNodeExecutor
#是否打印执行中过程中的日志,默认为true
print-execution-log: true
#是否开启本地文件监听,默认为false
enable-monitor-file: false
#是否开启快速解析模式,默认为false
fast-load: false
#简易监控配置选项
monitor:
#监控是否开启,默认不开启
enable-log: false
#监控队列存储大小,默认值为200
queue-limit: 200
#监控一开始延迟多少执行,默认值为300000毫秒,也就是5分钟
delay: 300000
#监控日志打印每过多少时间执行一次,默认值为300000毫秒,也就是5分钟
period: 300000
上面是官网给出的详细配置项,具体可以参考,下面是我项目里使用到的配置项
liteflow:
# 指定规则文件路径
ruleSource : liteflow/*.el.xml
# 重试次数
retry-count: 0
print-execution-log: true
monitor:
#监控是否开启,默认不开启
enable-log: true
#监控队列存储大小,默认值为200
period: 300000
#自定义请求ID的生成类
request-id-generator-class: com.llp.liteflow.config.AppRequestIdGenerator
# 上下文的最大数量槽
slot-size : 10240
# 线程数,默认为64
main-executor-works: 64
# when 节点全局异步线程池最大线程数
when-max-workers: 16
# when 节点全局异步线程池队列数
when-queue-limit: 5120
# 在启动的时候就解析规则
parse-on-start: true
enable: true
4.代码实现
自定义请求ID的生成类
@Data
public class AppRequestIdGenerator implements RequestIdGenerator {
public static final Snowflake flake = new Snowflake();
@Override
public String generate() {
return flake.nextIdStr();
}
}
上下文
@Data
public class AppFlowContext {
private String text;
}
编写规则表达式
参考https://liteflow.cc/pages/a590ee/#%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95
orderFlow.el.xml
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<!--
1.验证用户信息:确保用户登录状态有效。
2.准备交易:生成订单并锁定库存。
3.处理支付:调用支付网关完成支付。
4.更新订单状态:根据支付结果更新订单状态。
5.发送通知:通过邮件或短信通知用户支付结果。
-->
<chain name="orderFlow">
THEN(
verifyUser,
prepareTrade,
processPayment,
updateOrderStatus,
WHEN(sendEmail, sendPhone)
);
</chain>
</flow>
<!-- # 文件编排, then 代表串行执行 when 表示并行执行-->
<!-- # 串行编排示例:同步执行-->
<!-- THEN(a, b, c, d);-->
<!-- # 并行编排示例:异步执行-->
<!-- WHEN(a, b, c);-->
<!-- # 串行和并行嵌套结合-->
<!-- THEN( a, WHEN(b, c, d), e);-->
<!-- # 选择编排示例: 通过组件a的返回值决定执行哪一个组件,如果a组件执行返回的组件名称是b则执行b-->
<!-- SWITCH(a).to(b, c, d);-->
<!-- # 条件编排示例 IF(x, a) x组件返回true时执行a-->
<!-- THEN(IF(x, a),b );-->
规则类
这里一共将业务校验拆分为了四个规则分别去处理:
1.验证用户信息:确保用户登录状态有效。
2.准备交易:生成订单并锁定库存。
3.处理支付:调用支付网关完成支付。
4.更新订单状态:根据支付结果更新订单状态。
5.发送通知:通过邮件或短信通知用户支付结果。
verifyUser
@Slf4j
//注意这里组件的名称要和前面的名称一致
@Component(value = "verifyUser")
public class VerifyUser extends NodeComponent {
@Override
public void process() throws Exception {
log.info("校验用户信息");
OrderReqVO requestData = this.getSlot().getRequestData();
log.info("requestData:{}",requestData);
/**
*在前面orderServiceImpl类中指定了上下文的类型,所以这里可以直接获取到上下文对象
* 并对上下文对象进行操作
*/
AppFlowContext context = this.getContextBean(AppFlowContext.class);
context.setText("verifyUser");
}
}
prepareTrade
@Slf4j
@Component(value = "prepareTrade")
public class PrepareTrade extends NodeComponent {
@Override
public void process() throws Exception {
log.info("准备交易");
OrderReqVO requestData = this.getSlot().getRequestData();
log.info("requestData:{}",requestData);
AppFlowContext context = this.getContextBean(AppFlowContext.class);
log.info("context:{}",context);
}
}
processPayment
@Slf4j
@Component(value = "processPayment")
public class ProcessPayment extends NodeComponent {
@Override
public void process() throws Exception {
log.info("处理支付");
}
}
updateOrderStatus
@Slf4j
@Component(value = "updateOrderStatus")
public class UpdateOrderStatus extends NodeComponent {
@Override
public void process() throws Exception {
log.info("更新订单状态");
}
}
sendEmail
@Slf4j
@Component(value = "sendEmail")
public class SendEmail extends NodeComponent {
@Override
public void process() throws Exception {
log.info("发送邮件");
}
}
sendPhone
@Slf4j
@Component(value = "sendPhone")
public class SendPhone extends NodeComponent {
@Override
public void process() throws Exception {
log.info("发送手机短信");
}
}
5.测试
/**
* 参考:https://blog.csdn.net/zhangguicai168/article/details/140726102
*/
@SpringBootApplication
public class LiteFlowApplication {
public static void main(String[] args) {
SpringApplication.run(LiteFlowApplication.class, args);
}
}
@Slf4j
@RestController
public class OrderController {
@Resource
private OrderService orderService;
/**
* 模拟订单支付流程信息
*/
@PostMapping(value = "/pay")
public String flow(@RequestBody OrderReqVO reqVO) {
orderService.handleApp(reqVO);
return "success";
}
}
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Resource
private FlowExecutor flowExecutor;
@Override
public void handleApp(OrderReqVO reqVO) {
//对应规则名称,我们可以将前置的业务校验使用liteflow去处理,后面只关注业务的实现
LiteflowResponse response = flowExecutor.execute2Resp("orderFlow", reqVO, 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 {}", JSONUtil.toJsonStr(context));
}
}
执行打印信息如下:
2025-02-05 10:47:39.433 INFO 27332 --- [nio-8081-exec-3] com.llp.liteflow.rule.VerifyUser : 校验用户信息
2025-02-05 10:47:39.436 INFO 27332 --- [nio-8081-exec-3] com.llp.liteflow.rule.PrepareTrade : 准备交易
2025-02-05 10:47:39.436 INFO 27332 --- [nio-8081-exec-3] com.llp.liteflow.rule.ProcessPayment : 处理支付
2025-02-05 10:47:39.436 INFO 27332 --- [nio-8081-exec-3] com.llp.liteflow.rule.UpdateOrderStatus : 更新订单状态
# 这里发送邮件和短信是并行处理
2025-02-05 10:47:39.451 INFO 27332 --- [lf-when-thead-0] com.llp.liteflow.rule.SendEmail : 发送邮件
2025-02-05 10:47:39.452 INFO 27332 --- [lf-when-thead-1] com.llp.liteflow.rule.SendPhone : 发送手机短信