LiteFlow 基本使用教程
轻量,快速,稳定可编排的组件式规则引擎
引用官网的介绍,LiteFlow就是为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用LiteFlow最合适不过。它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件,并支持热加载规则配置,实现即时修改。
需要注意的是,LiteFlow只做基于逻辑的流转,而不做基于角色任务的流转。如果你想做基于角色任务的流转,推荐使用flowable,activiti这2个框架。
官网地址:https://liteflow.yomahub.com/
规则文件
LiteFlow 支持 xml、json 和 yml 作为规则文件,主要由 Node 节点和 Chain 节点组成。在 Spring 体系统 Node 是非必须的。具体的 demo 可以到官网上面查看,我本人推荐使用 xml 文件格式,可读性强。json 和 yml 在这里并不是很适合。
LiteFlow 支持本地规则文件、ZK 规则文件以及自定义规则文件,具体使用那种就看公司要求了。本地的最简单配合主动刷新也可以获得良好的体验,如果公司项目已经部署了 ZK,那么使用 ZK 是最合适的,如果没有部署就没有必要了,用本地的就好。自定义的话 LiteFlow 提供了三个父类,ClassXmlFlowParser、ClassJsonFlowParser 和 ClassYmlFlowParser,用什么规则文件类型就继承那个,然后重写方法并返回 XXXContent 即可,还是蛮方便的。
同时 LiteFlow 也支持使用 Java 代码来构造 Node 节点,使用 LiteFlowNodeBuilder 可以对组件进行声明,但是感觉略显复杂,特定场景下可以使用,并没有规则文件好用。
在编写的时候可以给流程加上标签,方便在日志中展示。
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
<then value="a[tag1],b[tag2],c[tag3]"/>
</chain>
</flow>
基本使用
同步&异步编排
LiteFlow 支持同步和异步的任务调度,分别使用 then 和 when 来表示同步节点和异步节点。还有 pre 节点和 finally 节点表示前置和后置节点。这里要注意的就是框架会将同级节点进行合并,如果不注意这个的话会有意想不到的顺序问题。
<then value="a,b,c,d"/>
下面的方式和上面等价
<then value="a,b"/>
<then value="c,d"/>
在异步节点中,如果要区分多个任务,比如并行执行 a,b,等执行好了,再并行执行 c,d,就需要声明 group
<when group="g1" value="a,b"/>
<when group="g2" value="c,d"/>
还有几个参数:
- errorResume 相同异步并行组之间的抛错,如果为 true,则出错抛出异常后任然继续执行后续的任务
- any 异步任一线程结束即继续
流程与流程间支持签到,可以无限套娃。还支持在代码中隐式的在一个节点里通过代码调用另外一条流程,隐式调用可以完成更为复杂的子流程,比如循环调用。
执行器
执行器FlowExecutor用来执行一个流程,三种用法。推荐在业务系统中实现属于自己的Slot,方便流程中传递参数。执行器支持的类型还是挺丰富的,至少还有一个 Feature 可以使用,特定场景下使用还是很方便的。
### 返回类型为LiteflowResponse
//参数为流程ID,无初始流程入参
public LiteflowResponse<DefaultSlot> execute2Resp(String chainId)
//第一个参数为流程ID,第二个参数为流程入参。其中流程入参可以在组件中通过this.getSlot().getRequestData()来获得。
public LiteflowResponse<DefaultSlot> execute2Resp(String chainId, Object param);
//第一个参数为流程ID,第二个参数为流程入参,第三个参数为自定义的Slot类型
public LiteflowResponse<T> execute2Resp(String chainId, Object param, Class<T> slotClazz)
### 返回类型为Slot接口的子类
//参数为流程ID,无初始流程入参
public DefaultSlot execute(String chainId) throws Exception;
//第一个参数为流程ID,第二个参数为流程入参。其中流程入参可以在组件中通过this.getSlot().getRequestData()来获得。
public DefaultSlot execute(String chainId,Object param) throws Exception;
//第一个参数为流程ID,第二个参数为流程入参,第三个参数为自定义的Slot类型
public <T extends Slot> T execute(String chainId, Object param, Class<T> slotClazz) throws Exception
### 返回类型为Future
//第一个参数为流程ID,第二个参数为流程入参,第三个参数为自定义的Slot类型
public <T extends Slot> Future<LiteflowResponse<T>> execute2Future(String chainId, Object param, Class<T> slotClazz)
数据槽
在执行器执行流程时会分配唯一的一个数据槽给这个请求。不同请求的数据槽是完全隔离的。你可以理解为数据槽就是这个请求中的上下文,里面存放着此请求所有的数据。不同的组件之间是不传递参数的,所有的数据交互都是通过这个数据槽来实现的。
无论你使用DefaultSlot还是自定义的Slot,Slot会有一些元方法供调用:
getRequestId():每一个链路在执行初期都会生成这个链路的唯一ID,同时这个ID也会打印在日志中。方便于追踪。这个方法能得到这个链路追踪ID。
getRequestData():获取链路的初始参数。
getChainName():获取链路的名称。
getException():得到链路中的异常信息,如果没有就为null。
getExecuteStepStr():得到链路中的执行步骤信息。
setData(K,V):往slot中设置一个值。
getData(K):从Slot里得到一个值。
普通组件
@LiteflowComponent("a")
public class ACmp extends NodeComponent {
@Override
public void process() {
System.out.println("ACmp executed!");
}
}
组件节点需要继承 NodeComponent 类,重写 process 方法。推荐重写 isAccess 方法,可以用于业务参数的预先判断。在组件节点里,随时可以通过方法getSlot获取当前的数据槽,从而可以获取任何数据。
还有一些方法,比如:isContinueOnError,isEnd 等方法。
条件组件
在实际业务中,往往要通过动态的业务逻辑判断到底接下去该执行哪一个节点。
<chain name="chain1">
<then value="a,c(b|d)"/> <!-- c是路由节点,根据c里的逻辑决定路由到b节点还是d节点,可以配置多个 -->
<then value="e,f,g"/>
</chain>
需要实现方法processCond,这个方法需要返回String类型,就是具体的结果节点
@LiteflowComponent("e")
public class ECmp extends NodeCondComponent {
@Override
public String processCond() throws Exception {
System.out.println("Ecomp executed!");
return "g";
}
}
其他
使用 this.sendPrivateDeliveryData() 方法可以进行参数投递,被投递的参数只能被获取一次,在一些特定的场景中可以使用该方法。
LiteFlow 还支持组件重试,平滑热刷新(flowExecutor.reloadRule() 方法调用即可),全局切面,异常处理等可以到官网进行查看文档。