在源码的test目录下有quickstart测试用例(easyflow\easyflow-flow\src\test\java\com\jd\easyflow\flow\quickstart\QuickStartTest.java),可直接运行或调试以了解使用方式和运行原理。
具体实践步骤如下:
以maven为例:
<dependency>
<groupId>com.jd.easyflow</groupId>
<artifactId>easyflow-flow</artifactId>
<version>{替换为最新版本}</version>
</dependency>
以node001->node002→node003的执行顺序为例:
{"id": "quickstart_001", "name": "Quick Start 001",
"nodes": [
{"id": "node001","name": "Node001","action": {"createExp": "new com.jd.easyflow.flow.quickstart.QuickStart001Node01Action()"},"start": true,"post": {"to": "node002"}},
{"id": "node002","name": "Node002","action": {"createExp": "new com.jd.easyflow.flow.quickstart.QuickStart002Node01Action()"},"post": {"to": "node003"}},
{"id": "node003","name": "Node003","action": {"createExp": "new com.jd.easyflow.flow.quickstart.QuickStart003Node01Action()"}}
]
}
其中QuickStart001Node01Action等为java节点动作类
FlowEngineImpl flowEngine = new FlowEngineImpl();
flowEngine.setFlowPath("classpath:flow/quickstart/quickstart_001.json");
flowEngine.init();
Spring环境可直接定义FlowEngineImpl bean.
FlowParam param = new FlowParam("quickstart_001");
FlowResult result = flowEngine.execute(param);
完整测试用例的执行结果打印如下:
[main ] INFO FlowEngineImpl - Start parsing definition files:easyflow-flow/target/test-classes/flow/quickstart/quickstart_001.json
[main ] INFO FlowEngineImpl - SART EXECUTE FLOW, flowId:quickstart_001 nodeIds:null
[main ] INFO BaseFlowRunner - EXECUTE NODE:node001
[main ] INFO QuickStart001Node01Action - Execute Node 001
[main ] INFO BaseFlowRunner - NEXT NODES:node002
[main ] INFO BaseFlowRunner - EXECUTE NODE:node002
[main ] INFO QuickStart002Node01Action - Execute Node 002
[main ] INFO BaseFlowRunner - NEXT NODES:node003
[main ] INFO BaseFlowRunner - EXECUTE NODE:node003
[main ] INFO QuickStart003Node01Action - Execute Node 003
[main ] INFO BaseFlowRunner - NEXT NODES:
[main ] INFO QuickStartTest - Execute finish, current node is:node003
一级元素 | 二级元素 | 三级元素 | 名称 | 说明 |
---|---|---|---|---|
id | 流程ID | 全局唯一 | ||
name | 流程名称 | |||
nodes | 节点列表 | |||
id | 节点ID | 流程定义内唯一 | ||
name | 节点名称 | |||
action | 节点动作 | |||
exp | 执行的 spel 表达式 | |||
createExp | 节点动作的创建表达式 | 返回结果必须为 NodeAction 接口的实现 | ||
flow | 子流程定义 | 子流程定义 | ||
flowId | 子流程 ID | 子流程 ID | ||
startNodeId | 子流程开始节点 ID | 子流程开始节点 ID,格式为字符串或字符串数组 | ||
post | 节点后置处理器 | 主要控制后继节点逻辑,目前支持: 固定后继节点 条件后继节点 动态计算 具体配置方式见后 | ||
listeners | 监听器列表 | |||
createExp | 监听器创建表达式 | |||
filters | 流程过滤器列表 | |||
nodeFilters | 节点过滤器列表 | |||
nodePreHandlerFilters | 节点前置处理过滤器 | |||
createExp | 过滤器创建表达式 | |||
nodeActionFilters | 节点动作过滤器列表 | |||
createExp | 过滤器创建表达式 | |||
NodePostHandlerFilters | 节点后置处理过滤器 | |||
createExp | 过滤器创建表达式 | |||
runner | 流程执行器 | 默认为串行执行器,可配置为多线程执行器。 | ||
createExp | 流程执行器表达式 | |||
properties | 流程属性 | |||
flow.recordHistory | 是否记录流程执行的节点历史 | 默认为是。如果一次流程运行执行非常多次(千万或亿或死循环,一般不会发生),需要设为 false | ||
post有如下几种配置规范:
一、固定值
1、{"to":XXX},到to节点
二、条件类
2、{"when":XXX, "to":XXX},当when条件满足时到to节点
3、{"conditions":[{"when":XXX, "to":XXX},{"when":XXX, "to":XXX}]},多个条件
when为el表达式
条件类可配置参数conditionType,取值有exclusive/inclusive,默认为exclusive,只要一个分支条件判断成功,则判断逻辑终止;
条件类可配置参数defaultTo,当条件没有满足的时的默认分支
三、创建表达式
4、{"createExp":XXX},流程解析时执行此表达式,计算值为一个NodePostHandler的实现类
四、表达式
5、{"exp":XXX},流程运行时执行此表达式,计算值为to配置(见下)可接受的类型
如果为字符串,如果以开头,则代表索引值,取值有first, last,previous, $next,否则代表固定的节点ID
如果为整数,则代表节点索引值
如果为List,则代表字符串或整数值列表
如果为Map,则可以配置"exp":"XXX",根据EL值动态计算后继节点,具体的值类型为字符串、整数或List
配置示例见test目录相关用例。
流程执行过程中变量
名称 | 类型 | 说明 |
---|---|---|
context | FlowContext | 流程上下文 |
param | FlowParam | 流程参数 |
bizParam | 依赖业务传入 | FlowParam中的param |
paramData | Map | 对应FlowParam中的dataMap |
result | FlowResult | 流程结果 |
bizResult | 依赖业务传入 | FlowResult中的result |
nodeContext | NodeContext | 节点上下文 |
actionResult | 依赖具体接口实现 | 节点动作的执行结果 |
过滤器和监听器均为横向控制的方式,区别在于监听器侧重监听,对流程的控制有限,过滤器侧重过滤,可以捕获异常或流程处理等。
默认情况下,流程引擎不捕获和封装异常,业务逻辑中抛出的异常直接抛出;对于多线程执行场景下,如果多个节点同时有异常,会任选其一抛出,同时可以从流程上下文中获取所有异常。
对于节点异常可以通过节点过滤器统一捕获做业务逻辑处理,或者可通过流程过滤器统一捕获做业务逻辑处理。
===============================
下一章将专题介绍流程引擎的实现原理