SpringBoot + LiteFlow实现流程编排
LiteFlow简介
官网地址
应用背景
当我们的系统随着业务的复杂度越来越高,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部资源调取,内部其他系统RPC调用等等。各个模块之间的耦合度很高。LiteFlow是一个非常强大的现代化的规则引擎框架,融合了编排特性和规则引擎的所有特性。。
LiteFlow适用于拥有复杂逻辑的业务,比如说价格引擎,下单流程等,这些业务往往都拥有很多步骤,这些步骤完全可以按照业务粒度拆分成一个个独立的组件,进行装配复用变更。使用LiteFlow,你会得到一个灵活度高,扩展性很强的系统。因为组件之间相互独立,也可以避免改一处而动全身的这样的风险。
注意:LiteFlow只做基于逻辑的流转,而不做基于角色任务的流转。如果你想做基于角色任务的流转,推荐使用flowable,activiti这2个框架。
环境支持
LiteFlow要求的最低的JDK版本为8,支持JDK8~JDK17所有的版本。如果你使用JDK11以上,确保LiteFlow的版本为v2.10.6及其以上版本。
LiteFlow要求的Springboot的最低的版本是2.0。支持的范围是Springboot 2.X ~ Springboot 3.X。当然如果你使用了最新的Springboot 3.X,相应的JDK版本也要切换为JDK17。
LiteFlow使用
引入依赖
<dependency> <groupId>com.yomahub</groupId> <artifactId>liteflow-spring-boot-starter</artifactId> <version>2.11.1</version>
</dependency>
配置项
LiteFlow有诸多配置项,大多数配置项有默认值,可以不必配置,同时官方也建议某个配置项不了解它有什么用时,就不要去随意的改它的值。
liteflow:#规则文件路径rule-source: config/flow.el.xml#-----------------以下非必须-----------------#liteflow是否开启,默认为trueenable: true#liteflow的banner打印是否开启,默认为trueprint-banner: true#zkNode的节点,只有使用zk作为配置源的时候才起作用,默认为/lite-flow/flowzk-node: /lite-flow/flow#上下文的最大数量槽,默认值为1024slot-size: 1024#FlowExecutor的execute2Future的线程数,默认为64main-executor-works: 64#FlowExecutor的execute2Future的自定义线程池Builder,LiteFlow提供了默认的Buildermain-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder#自定义请求ID的生成类,LiteFlow提供了默认的生成类request-id-generator-class: com.yomahub.liteflow.flow.id.DefaultRequestIdGenerator#并行节点的线程池Builder,LiteFlow提供了默认的Builderthread-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultWhenExecutorBuilder#异步线程最长的等待时间(只用于when),默认值为15000when-max-wait-time: 15000#异步线程最长的等待时间(只用于when),默认值为MILLISECONDS,毫秒when-max-wait-time-unit: MILLISECONDS#when节点全局异步线程池最大线程数,默认为16when-max-workers: 16#并行循环子项线程池最大线程数,默认为16parallelLoop-max-workers: 16#并行循环子项线程池等待队列数,默认为512parallelLoop-queue-limit: 512#并行循环子项的线程池Builder,LiteFlow提供了默认的BuilderparallelLoop-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultParallelLoopExecutorBuilder#when节点全局异步线程池等待队列数,默认为512when-queue-limit: 512#是否在启动的时候就解析规则,默认为trueparse-on-start: true#全局重试次数,默认为0retry-count: 0#是否支持不同类型的加载方式混用,默认为falsesupport-multiple-type: false#全局默认节点执行器node-executor-class: com.yomahub.liteflow.flow.executor.DefaultNodeExecutor#是否打印执行中过程中的日志,默认为trueprint-execution-log: true#是否开启本地文件监听,默认为falseenable-monitor-file: false#是否开启快速解析模式,默认为falsefast-load: false#简易监控配置选项monitor:#监控是否开启,默认不开启enable-log: false#监控队列存储大小,默认值为200queue-limit: 200#监控一开始延迟多少执行,默认值为300000毫秒,也就是5分钟delay: 300000#监控日志打印每过多少时间执行一次,默认值为300000毫秒,也就是5分钟period: 300000
注意:只要使用规则,则必须配置rule-source配置,但是如果你是用代码动态构建规则,则rule-source自动失效。
规则文件
LiteFlow支持多种规则文件源配置:本地文件,数据库,zk,Nacos,Apollo,Etcd,Redis以及自定义配置源。LiteFlow支持3种规则文件格式:XML,JSON,YML,3种文件的配置相差无几。LiteFlow的组成很轻量,主要由Node以及Chain元素构成。
<?xml version="1.0" encoding="UTF-8"?>
<flow> <chain name="chain1"> THEN(a, b, c); </chain> <chain name="scChain"> SWITCH(s1).to(s2, THEN(a,b).id("d")); </chain>
</flow>
组件
在介绍具体的组件之前,我们先来了解下@LiteflowComponent注解。
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
public @interface LiteflowComponent { @AliasFor(annotation = Component.class, attribute = "value") String value() default ""; @AliasFor(annotation = Component.class, attribute = "value") String id() default ""; /*** 可以给节点起别名**/String name() default ""; }
@LiteflowComponent继承自@Component注解,在Spring环境中,可以将组件注入到容器中。它的value或者id即对应规则文件中的node的id。例如上述规则文件中的a,b,c等。
1. 普通组件:NodeComponent
普通组件节点需要继承NodeComponent,需要实现process方法。可用于THEN和WHEN编排中。
@LiteflowComponent("a")
public class AComponent extends NodeComponent { @Override public void process() throws Exception { System.out.println("执行A规则"); }
}
当然NodeComponent中还有一些其他方法可以重写,以达到自己的业务需求。例如:
- isAccess():表示是否进入该节点,可以用于业务参数的预先判断。
- isContinueOnError():表示出错是否继续往下执行下一个组件,默认为false
- isEnd():是否结束整个流程(不往下继续执行)。如果返回true,则表示在这个组件执行完之后立马终止整个流程。此时由于是用户主动结束的流程,属于正常结束,所以流程结果中(LiteflowResponse)的isSuccess是true。
- beforeProcess()和afterProcess():流程的前置和后置处理器,其中前置处理器,在isAccess 之后执行。
- onSuccess()和onError():流程的成功失败事件回调
- rollback():流程失败后的回滚方法。
组件节点内部,使用this关键字
-
获取流程初始入参参数
我们在组件节点内部可以通过this.getRequestData()去获取流程初始的入参。例如:
@LiteflowComponent("a") public class AComponent extends NodeComponent { @Override public void process() throws Exception { DataRequest dataRequest = this.getRequestData(); System.out.println("执行A规则"); } }
-
获取上下文
在组件节点里,随时可以通过方法this.getContextBean(clazz)获取当前你自己定义的上下文,从而可以获取到上下文的数据。例如:@LiteflowComponent("a") public class AComponent extends NodeComponent { @Override public void process() throws Exception { ConditionContext context = this.getContextBean(ConditionContext.class); System.out.println("执行A规则"); } }
-
setIsEnd
是否立即结束整个流程 ,用法为this.setIsEnd(true)。
2. 选择组件:NodeSwitchComponent
实际业务中,我们针对不同的业务类型,有不同的业务处理逻辑,例如上一篇文章中的订单类型一样,此时就需要节点动态的判断去执行哪些节点或者链路,所以就出现了选择组件。
选择组件需要实现NodeSwitchComponent,并且需要实现processSwitch()方法。用于SWITCH编排中。
processSwitch()方法返回值是一个String,即下一步流程执行的节点ID或者链路tag。