LiteFlow 组件式规则引擎
什么是LiteFlow
通过LiteFlow,你可以将流式代码结构,转变成以组件为核心概念的代码结构,这种结构的好处是可以任意编排,业务之间是解耦的,任务之间的流转全靠规则来驱动。
liteflow 简单案例:
复杂的图示:
提示:LiteFlow只做基于逻辑的流转,而不做基于角色任务的流转。因此无法实现审批流(A审批完应该是B审批,然后再流转到C角色)
使用
1.2.1 引入pom
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring</artifactId>
<version>2.12.4.1</version>
</dependency>
1.2.2 LiteFlow 工具介绍
1.2.2.1 执行器
正常注入即可
@Resource
private FlowExecutor flowExecutor;
使用时:
//第一个参数为流程ID,第二个参数为流程入参,后面可以传入多个上下文class
public LiteflowResponse execute2Resp(String chainId, Object param, Class<?>// ... contextBeanClazzArray)
//第一个参数为流程ID,第二个参数为流程入参,后面可以传入多个上下文的Bean
public LiteflowResponse execute2Resp(String chainId, Object param, Object// ... contextBeanArray)
1.2.2.2 上下文对象
-
数据上下文这个概念在LiteFlow框架中非常重要,你所有的业务数据都是放在数据上下文中。
-
平时我们写瀑布流的程序时,A调用B,那A一定要把B所需要的参数传递给B,而在LiteFlow框架体系中,每个组件的定义中是不需要接受参数的,也无任何返回的。
每个组件只需要从数据上下文中获取自己关心的数据即可,而不用关心此数据是由谁提供的,同样的,每个组件也只要把自己执行所产生的结果数据放到数据上下文中即可,也不用关心此数据到底是提供给谁用的。这样一来,就从数据层面一定程度的解耦了。从而达到可编排的目的
定义:
@Data
@ContextBean("anyName") // 设置别名
public class XxxFlowContext {
// ...
}
传入上下文
XxxFlowContext context = new XxxFlowContext();
LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, context);
使用
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON, nodeId = "b")
public void processB(NodeComponent bindCmp) {
XxxFlowContext context = bindCmp.getContextBean(XxxFlowContext.class);
//从context中取到业务数据进行处理
context.getxxx();
// ...
}
1.2.2.3 声明式组件
类级别的组件
@LiteflowComponent("aComponent")
public class AComponent {
@LiteflowMethod(LiteFlowMethodEnum.PROCESS, nodeType = NodeTypeEnum.COMMON)
public void processAcmp(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
@LiteflowMethod(LiteFlowMethodEnum.IS_ACCESS)
public boolean isAcmpAccess(NodeComponent bindCmp) {
return true;
}
@LiteflowMethod(LiteFlowMethodEnum.BEFORE_PROCESS)
public void beforeAcmp(NodeComponent bindCmp) {
System.out.println("before A");
}
@LiteflowMethod(LiteFlowMethodEnum.AFTER_PROCESS)
public void afterAcmp(NodeComponent bindCmp) {
System.out.println("after A");
}
@LiteflowMethod(LiteFlowMethodEnum.ON_SUCCESS)
public void onAcmpSuccess(NodeComponent bindCmp) {
System.out.println("Acmp success");
}
@LiteflowMethod(LiteFlowMethodEnum.ON_ERROR)
public void onAcmpError(NodeComponent bindCmp, Exception e) {
System.out.println("Acmp error");
}
@LiteflowMethod(LiteFlowMethodEnum.IS_END)
public boolean isAcmpEnd(NodeComponent bindCmp) {
return false;
}
@LiteflowMethod(value = LiteFlowMethodEnum.ROLLBACK)
public void rollbackA(NodeComponent bindCmp) throws Exception {
System.out.println("ACmp rollback!");
}
}
类级别的组件
@LiteflowComponent
public class CmpConfig {
/**
* 普通组件的定义
*/
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a", nodeName = "A组件")
public void processA(NodeComponent bindCmp) {
// ...
}
/**
* SWITCH组件的定义
*/
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH, nodeId = "b", nodeName = "B组件", nodeType = NodeTypeEnum.SWITCH)
public String processB(NodeComponent bindCmp) {
// ...
}
/**
* 布尔组件的定义
*/
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_BOOLEAN, nodeId = "c", nodeName = "C组件", nodeType = NodeTypeEnum.BOOLEAN)
public boolean processC(NodeComponent bindCmp) {
// ...
}
/**
* FOR组件的定义
*/
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_FOR, nodeId = "d", nodeName = "D组件", nodeType = NodeTypeEnum.FOR)
public int processD(NodeComponent bindCmp) {
// ...
}
/**
* 迭代组件的定义
*/
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_ITERATOR, nodeId = "e", nodeName = "E组件", nodeType = NodeTypeEnum.ITERATOR)
public int processE(NodeComponent bindCmp) {
// ...
}
}
1.2.3 构造规则
EL表达式
THEN(node("a"),WHEN(node("b"),THEN(node("c"),node("d"))),node("e"))
1.2.3.1 串行
THEN(a, b, THEN(c, d));
THEN(a, b, c, d);
1.2.3.2 并行
THEN(a, WHEN(b, c, d), e);
==注意:==目前liteflow设计里when线程池,如果你不单独设置自定义线程池,那么就会用默认的线程池。而这个线程池,是所有的when共同一个
你可以如下配置来开启:
liteflow.when-thread-pool-isolate=true
1.2.3.3 选择
SWITCH(a).to(b, c, d);
1.2.3.4 条件
THEN( IF(x, a),b);
1.2.3.5 循环
FOR(5).DO(THEN(a, b));
WHILE(w).DO(THEN(a, b));
ITERATOR(x).DO(THEN(a, b));# ITERATOR迭代循环表达式通常用于集合的循环
FOR(f).DO(THEN(a, b)).BREAK(c); # LiteFlow同样也支持BREAK语法,代表退出循环。
1.3 Demo
以进修生审核流程为例
步骤为:
上下文对象:
@Data
public class ApplyFlowContext {
/**
* 审核数组
*/
private List<ApplyInfo> applyInfoList;
/**
* 审核意见
*/
private String reviewOpinion;
/**
* 审核状态
*/
private ApplyStatusEnum applyStatus;
}
组件:
@Slf4j
@LiteflowComponent
public class ApplyFlowMethod {
/**
* 选择节点
*/
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH, nodeId = "chooseApplyNode", nodeName = "选择节点", nodeType = NodeTypeEnum.SWITCH)
public String chooseApplyNode(NodeComponent bindCmp) {
ApplyFlowContext applyFlowContext = bindCmp.getContextBean(ApplyFlowContext.class);
return applyFlowContext.getApplyStatus().getChainNodeName(); // 此处的返回值是el语句里的id
}
/**
* 审核通过
*/
@GlobalTransactional(rollbackFor = Exception.class)
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "applySuccess", nodeName = "申请通过")
public void applySuccess(NodeComponent bindCmp) {
ApplyFlowContext applyFlowContext = bindCmp.getContextBean(ApplyFlowContext.class);
List<ApplyInfo> applyInfoList = applyFlowContext.getApplyInfoList();
// ...
}
/**
* 审核不通过
*/
@GlobalTransactional(rollbackFor = Exception.class)
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "applyFail", nodeName = "审核不通过")
public void applyFail(NodeComponent bindCmp) {
ApplyFlowContext applyFlowContext = bindCmp.getContextBean(ApplyFlowContext.class);
// ...
}
/**
* 发送录取消息
*/
@GlobalTransactional(rollbackFor = Exception.class)
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "sendPassMsg", nodeName = "发送录取消息")
public void sendPassMsg(NodeComponent bindCmp) {
ApplyFlowContext applyFlowContext = bindCmp.getContextBean(ApplyFlowContext.class);
List<ApplyInfo> applyInfos = applyFlowContext.getApplyInfoList();
// ...
}
}
EL:
SWITCH(chooseApplyNode) .TO(THEN(applySuccess,sendPassMsg).id("applySuccess"),THEN(applyFail).id("applyFail"));
执行器
/**
* 申请
*/
public void apply(List<ApplyInfo> applyInfos, ApplyStatusEnum applyStatusEnum, Boolean autoSendMsg) {
// 组织上下文
ApplyFlowContext applyFlowContext = new ApplyFlowContext();
applyFlowContext.setApplyInfoList(applyInfos);
applyFlowContext.setApplyStatus(applyStatusEnum);
// 获取liteFlow配置 此处是从数据库读取
LiteFlow liteFlow = liteFlowService.getByChainId("申请流程");
String chainId = liteFlow.getChainId();
String elContent = liteFlow.getFlowContent();
String param = liteFlow.getParam();
LiteFlowChainELBuilder.createChain().setChainId(chainId).setEL(elContent).build();
// 使用的规则文件,传递参数,上下文对象
LiteflowResponse response = flowExecutor.execute2Resp(chainId, param, applyFlowContext);
// 获取流程执行后的结果
if (!response.isSuccess()) {
Exception e = response.getCause();
log.warn("执行失败:{}", e.getCause(), e);
}
}