xml
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.12.4.1</version>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>2.15.1</version>
</dependency>[!quote] LiteFlow
LiteFlow 是一个业务规则编排引擎,而不是流程引擎
- 通过统一的 xml 文件编排逻辑规则,使得逻辑类之间松耦合,不用互相引用
- LiteFlow 相当于瀑布流,没有办法暂停
如果你使用 JDK11 及其以上的版本,要在 jvm 参数加上 :
bash
--add-opens java.base/sun.reflect.annotation=ALL-UNNAMEDLiteFlow 是一个业务规则编排引擎,而不是流程引擎
流程引擎 : 流程是有角色的,比如说审批流 规则引擎 : 规则是一套相对复杂的逻辑块
❤️ 快速开始
- 定义组件
java
@LiteflowComponent
public class TestComponent {
// 普通组件
@LiteflowMethod(nodeType = NodeTypeEnum.COMMON, // 组件类型 - 普通组件
value = LiteFlowMethodEnum.PROCESS, // 组件方法类型 - 处理方法
nodeId = "a", // 组件ID
nodeName = "A组件")
public void processA(NodeComponent bindCmp) {
System.out.println("A组件执行了");
}
// SWITCH组件
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,
nodeId = "b",
nodeName = "B组件",
nodeType = NodeTypeEnum.SWITCH)
public String processB(NodeComponent bindCmp) {
return "c";
}
// 布尔组件 ……
// FOR组件 ……
// 迭代组件 ……
}- 编排组件
yml
# 主yml文件
liteflow:
rule-source: application-liteflow.xml # 规则文件路径,在resources下xml
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
THEN( a, b );
</chain>
</flow>- 执行业务逻辑
java
@Resource
private FlowExecutor flowExecutor;
@Test
void test_1() {
flowExecutor.execute2Resp("chain1", "test");
}❤️ 配置
yml
liteflow:
rule-source: application-liteflow-raffle.xml, application-liteflow-activity.xml
print-execution-log: false # 是否打印日志❤️ 组件
所有在组件中定义的方法都是有类型的~~【处理方法,预处理方法,前置处理方法 ……】~~,所有的这些方法的返回值都要按照 NodeComponent 来写
💛 普通组件
process该组件的业务逻辑方法isAccess组件的预处理方法,是否进入该组件isContinueOnError出错了是否往下继续执行,【默认 false】isEnd- true 组件执行完之后,立马终止整个流程。
属于正常结束
- true 组件执行完之后,立马终止整个流程。
beforeProcess/beforeProcess是 process 处理方法的前置/后置执行器,在 isAccess 之后执行,不推荐使用onSuccess/onError流程成功/失败的回调rollback流程失败后的回滚方法
java
@LiteflowMethod(nodeType = NodeTypeEnum.COMMON, // 组件类型 - 普通组件
value = LiteFlowMethodEnum.BEFORE_PROCESS, // 组件方法类型 - 前置处理
nodeId = "a", // 组件ID
nodeName = "A组件")
public void beforeProcessA(NodeComponent bindCmp) {
System.out.println("A 组件的 beforeProcessA 执行了");
}
@LiteflowMethod(nodeType = NodeTypeEnum.COMMON, // 组件类型 - 普通组件
value = LiteFlowMethodEnum.PROCESS, // 组件方法类型 - 处理方法
nodeId = "a", // 组件ID
nodeName = "A组件")
public void processA(NodeComponent bindCmp) {
System.out.println("A 组件的 processA 执行了");
}
@LiteflowMethod(nodeType = NodeTypeEnum.COMMON, // 组件类型 - 普通组件
value = LiteFlowMethodEnum.ON_SUCCESS, // 组件方法类型 - 处理成功处理
nodeId = "a", // 组件ID
nodeName = "A组件")
public void onSuccessA(NodeComponent bindCmp) {
System.out.println("A 组件的 onSuccessA 执行了");
}
---
A 组件的 beforeProcessA 执行了
A 组件的 processA 执行了
A 组件的 onSuccessA 执行了💛 选择组件
选择组件 可以通过动态的业务逻辑判断接下去该执行哪一个节点
java
/**
* 活动单类型路由器
*/
@LiteflowMethod(nodeType = NodeTypeEnum.SWITCH,
value = LiteFlowMethodEnum.PROCESS_SWITCH,
nodeId = "ActivityOrderTypeRouter",
nodeName = "活动单类型路由器")
public String ActivityOrderTypeRouter(NodeComponent bindCmp) {
return "nodeId";
}xml
<chain name="chain1">
SWITCH(a).to(b, c);
</chain>💛 布尔组件
java
@LiteflowMethod(nodeType = NodeTypeEnum.BOOLEAN, // 组件类型 - 布尔组件
value = LiteFlowMethodEnum.PROCESS_BOOLEAN, // 组件方法类型 - boolean处理方法
nodeId = "c",
nodeName = "C组件")
public boolean processC(NodeComponent bindCmp) {
System.out.println("C 组件执行了");
return true;
}xml
<chain name="RaffleFilterChain">
IF(CheckProceed, NormalTimeMatchRafflePoolFilter)
</chain>NodeComponent
java
public void processA(NodeComponent bindCmp) { …… }- 【改】
setIsEnd(boolean)是否立即结束整个流程
- 【查】
getContextBean(clazz)获取当前你自己定义的上下文,从而可以获取任何数据getNodeId获取组件 IDgetName获取组件名getChainName获取当前执行的流程名getRequestData获取流程的初始参数getTag获取组件的标签信息invoke/invoke2Response隐式调用,在该组件中调用另一个组件
❤️ 编排
yml
# 主yml文件
liteflow:
rule-source: application-liteflow.xml # 规则文件路径xml
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
THEN( a, b );
</chain>
</flow>❤️ 流程入参
流程入参能做的数据上下文都能实现
❤️ 数据上下文
[!hint] 所有的组件需要用到其他组件的数据时,都是利用数据上下文去取,而不是依赖于其他组件
DefaultContext :是默认实现的数据上下文,你也可以自己定义
setData传入参数T getData获取参数,拿到的参数类型需要自己强转hasData判断是否有参数
自定义数据上下文 :自定义数据上下文不需要继承什么,就直接定义一个类就好了,然后可以在组件中取出:
java
@Data
public class RaffleFilterContext{ …… }java
RaffleFilterContext context = bindCmp.getContextBean(RaffleFilterContext.class);传入 :
java
// 初始化上下文对象作为入参
DefaultContext defaultContext = new DefaultContext();
defaultContext.setData("key1", true);
flowExecutor.execute2Resp("chain2", null, defaultContext);获取 :
- 手动获取
java
@LiteflowMethod( …… )
public boolean processC(NodeComponent bindCmp) {
System.out.println("C 组件执行了");
// 如果在这里修改了DefaultContext,下一个组件获取时,就会拿到修改后的值,修改的是上下文的引用
return bindCmp.getContextBean(DefaultContext.class).getData("key1");
}❤️ 执行器
执行器 是一个流程的触发点,你可以在代码的任意地方用执行器进行执行流程
java
@Resource
private FlowExecutor flowExecutor;💛 阻塞执行
LiteflowResponse execute2Resp(String chainId, Object param, Class<?>... contextBeanClazzArray)第一个参数为流程 ID,第二个参数为流程入参,后面可以传入多个上下文 classLiteflowResponse execute2Resp(String chainId, Object param, Object... contextBeanArray)第一个参数为流程 ID,第二个参数为流程入参,后面可以传入多个上下文的 Bean
[!quote] LiteflowResponse LiteflowResponse 是执行器的执行结果
getContextBean(上下文class对象)获取上下文isSuccess()流程执行是否成功Exception getCause()获取异常信息
💛 非阻塞执行
Future<LiteflowResponse> execute2Future(String chainId, Object param, Object... contextBeanArray)
默认配置 :
yml
liteflow:
# 主线程池中的工作线程数
main-executor-works: 64
# 配置线程池实现类
main-executor-class: com.yomahub.liteflow.thread.LiteFlowDefaultMainExecutorBuilder自定义线程池实现类 :
java
public class CustomThreadBuilder implements ExecutorBuilder {
@Override
public ExecutorService buildExecutor() {
return Executors.newCachedThreadPool();
}
}❤️ 决策路由
决策路由会并行执行你指定的多条 chain,若 route 为 false,则终止执行
List<LiteflowResponse> executeRouteChain(流程入参, 数据上下文)会执行所有带有<route>标签的 chainList<LiteflowResponse> executeRouteChain(命名空间, 流程入参, 数据上下文)会执行指定命名空间下的所有带<route>标签的 chain
java
<chain name="chain1" namespace="n1">
<route>
AND(r1, r2, r3)
</route>
<body>
THEN(a, b, c);
</body>
</chain>
<chain name="chain2" namespace="n1">
<route>
AND(OR(r4, r5), NOT(r3))
</route>
<body>
SWITCH(x).TO(d, e, f);
</body>
</chain>
<chain name="chain3" namespace="n2">
<route>
r4
</route>
<body>
WHEN(a,b);
</body>
</chain>java
// 执行 n1 空间下的带 route 的 chain
flowExecutor.executeRouteChain("n1", null, YourContext);❤️ LiteFlowX 插件
❤️ 高级特性
💛 重试机制
xml
<chain id="chain1">
THEN(a, b.retry(3)),
THEN(a, b).retry(3, "java.lang.NullPointerException", "app.xlog.ggbond.raffle.service.filterChain.filters.RetryRouterException");
</chain>💛 前后置组件
前后置组件不受 exception 的影响
java
<chain name="chain1">
THEN(
PRE(p1, p2),
a, b, c,
FINALLY(f1, f2)
);
</chain>