使用指南 入门实践
在源码的test目录下有quickstart测试用例(easyfloweasyflow-flowsrctestjavacomjdeasyflowflowquickstartQuickStartTest.java),可直接运行或调试以了解使用方式和运行原理。
具体实践步骤如下:
1、代码中引入easyflow-flow jar包
以maven为例:
com.jd.easyflow easyflow-flow{替换为最新版本}
2、编写流程定义文件
以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节点动作类
3、编写应用启动时加载流程引擎的代码
FlowEngineImpl flowEngine = new FlowEngineImpl();
flowEngine.setFlowPath("classpath:flow/quickstart/quickstart_001.json");
flowEngine.init();
Spring环境可直接定义FlowEngineImpl bean.
4、编写具体流程调用执行的代码
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配置(见下)可接受的类型
to的配置说明
如果为字符串,如果以开头,则代表索引值,取值有first, last,previous, $next,否则代表固定的节点ID
如果为整数,则代表节点索引值
如果为List,则代表字符串或整数值列表
如果为Map,则可以配置"exp":"XXX",根据EL值动态计算后继节点,具体的值类型为字符串、整数或List
配置示例见test目录相关用例。
SPEL表达式固定变量
流程执行过程中变量
| 名称 | 类型 | 说明 |
|---|---|---|
| context | FlowContext | 流程上下文 |
| param | FlowParam | 流程参数 |
| bizParam | 依赖业务传入 | FlowParam中的param |
| paramData | Map | 对应FlowParam中的dataMap |
| result | FlowResult | 流程结果 |
| bizResult | 依赖业务传入 | FlowResult中的result |
| nodeContext | NodeContext | 节点上下文 |
| actionResult | 依赖具体接口实现 | 节点动作的执行结果 |
其他
过滤器和监听器使用说明
过滤器和监听器均为横向控制的方式,区别在于监听器侧重监听,对流程的控制有限,过滤器侧重过滤,可以捕获异常或流程处理等。
流程异常处理
默认情况下,流程引擎不捕获和封装异常,业务逻辑中抛出的异常直接抛出;对于多线程执行场景下,如果多个节点同时有异常,会任选其一抛出,同时可以从流程上下文中获取所有异常。
对于节点异常可以通过节点过滤器统一捕获做业务逻辑处理,或者可通过流程过滤器统一捕获做业务逻辑处理。
===============================
下一章将专题介绍流程引擎的实现原理



