Appearance
服务逻辑编排
服务逻辑编排是一种基于流的编程,是一种数据流编程范式,也是一种基于组件的软件工程方式。 通过将程序分解为可重用的组件,定义其输入和输出端口;再把多个组件连接起来,形成一个数据流图,就是一个服务逻辑进程; 多个服务逻辑进程就可以实现一个业务应用的服务逻辑。
服务的常规需求
一个服务接口,一般逻辑如下:
null
在这个过程中,复杂度主要集中在Service中,需要变量(定义、赋值)、判断、循环(跳出循环、进入下一个循环)、返回、异常(抛出和捕获)、事件(监听和触发)、定时执行、延时执行、调用(其他Service和其他接口)、事务和超时处理等。
变量
给变量赋予常量、时间以及其他表达式,可以实现变量赋值或者计算,通过组件完成
类似Java代码:
java
String a = '123';
a = a + 1;
Date now = new Date();
判断
可以提供跳过条件和排他网关、并行网关、包容网关,实现判断逻辑
跳过条件
在组件上设置跳过条件,当表达式成立时,跳过执行组件逻辑,直接进入后续逻辑
类似Java逻辑如下:
java
if(!skipCondition) {
// 执行业务逻辑
}
排他网关
按顺序,执行第一个满足条件的分支
类似Java逻辑如下:
java
if (conditionA) {
// 分支1
} else if (conditionB) {
// 分支2
} else {
// 默认分支
}
switch (key) {
case A:
// 分支1
break;
case B:
// 分支2
break;
default:
// 默认分支
break;
}
并行网关
逻辑编排中并行网关作用不大,由于机制问题,并行和串行没有太大差别;
汇聚规则:当所有入口线都执行完成后,才能往后执行
包容网关
执行满足条件的所有分支
类似Java逻辑如下:
java
if (conditionA || conditionB) {
if (conditionA) {
// 分支1
}
if (conditionB) {
// 分支2
}
} else {
// 分支1、2都不成立
}
汇聚规则:不存在激活的节点能到达网关时,即可往后执行
循环
使用多实例方式实现循环逻辑
类似Java逻辑如下:
java
for(Object item: items) {
// 业务逻辑
}
for(int i = 0; i < items.size(); i++){
Object item = items[i];
// 业务逻辑
}
多实例特征中,可以使用跳过条件来实现continue
,使用完成条件实现 break
多实例子流程中,也可以使用空结束事件和终止结束事件,分别实现循环中的 continue
和 break
类似Java逻辑如下:
java
for(int i = 0; i < items.size(); i++){
Object item = items[i];
if (conditionA) {
continue; // 空结束事件
}
...
if (conditionB) {
break; // 终止结束事件
}
...
}
代码块/内部方法
循环过程中,经常需要组合各种逻辑,此时可以使用子流程 SubProcess
实现
类似Java逻辑如下:
java
for(Object item: items){
// 代码块开始
item.disabled = false;
list.add(item)
...
// 代码块结束
}
返回
多分支场景时,可以采用终止结速事件来实现返回
类似Java逻辑如下:
java
if (condition){
return;
}
...
异常
组件执行有异常时,会触发对应的错误边界事件,没有定义错误边界事件时,会抛出异常;
类似Java逻辑如下:
java
try {
// 业务逻辑
} catch (Exection e) {
if (有对应的错误边界事件) {
// 触发错误边界事件
} else {
throw e;
}
}
通过错误结束事件,可以实现抛出自定义事件
类似Java逻辑如下:
java
throw new Exception('错误code')
事件
信号抛出中间事件和信号捕获中间事件,可以实现监听指定事件并执行对应逻辑的能力。信号默认在全局范围内传播,所有进程都可以监听到,可以通过设置scope
值为processInstance
将信号限制在一个Process实例中。
类似Java逻辑如下:
java
public class EventManager {
private List<EventObserver> observers = new ArrayList<>();
public void addObserver(EventObserver observer) {
observers.add(observer);
}
public void removeObserver(EventObserver observer) {
observers.remove(observer);
}
public void notifyObservers(String eventName) {
for (EventObserver observer : observers) {
if (observer.getEventName().equals(eventName)) {
observer.execute();
}
}
}
}
...
class MsgNameObserver implements EventObserver {
@Override
public String getEventName() {
return "msgName";
}
@Override
public void execute() {
// 你的逻辑代码
}
}
...
EventManager eventManager = new EventManager();
MsgNameObserver msgNameObserver = new MsgNameObserver();
eventManager.addObserver(msgNameObserver); // 监听事件
eventManager.notifyObservers("msgName"); // 触发事件
延时执行
定时器捕获中间事件,可以实现延时执行
类似Java逻辑如下:
java
Thread.sleep(1000);
如果是需要异步等待一定时间或定时执行逻辑,就教用定时执行Service
调用API
提供组件,实现各种类型的API调用
调用其他Service
使用CallAcivity组件,实现调用其他Service
事务
一个进程可以设定启用事务,当进程中局部组件需要独立事务时,可采用事务子流程。 针对一个事务范围内的所有数据库操作组件,如果共用一个数据源的,采用本地事务,否则采用JTA事务。
超时
一个进程可以设定超时时间,当时间超时后,进程中的组件将不再执行,并抛出超时异常。
每个组件也可以设置超时时间,当时间超时后,组件内部逻辑将不再执行(需要组件支持),多实例时,设置的超时时间为所有实例执行完成的时间,超时后,后续实例将不再执行,并抛出超时异常。
定时执行
由统一的任务调度服务管理所有进程的定时执行。也可以用API调用组件来自动添加、删除定时任务。
全局事件
由统一的事件总线完成,可以设置监听事件来启动进程执行。也可以用API调用组件来自动注册和触发事件。
进程的定义
像流程图一样,把多个可重用的组件连接成一个数据流图,即可定义一个进程,示例如下:
null
XML定义
参考 BPMN 定义规范,逻辑编排相关定义如下:
名称 | 节点名 | 说明 |
---|---|---|
进程 | Process | 每个逻辑编排一个进程 |
顺序流 | SequenceFlow | 组件执行顺序,有条件判断是否可以通行 |
网关
名称 | 节点名 | 说明 |
---|---|---|
排他网关 | ExclusiveGateway | 条件判断 |
并行网关 | ParallelGateway | 无异步任务时,和顺序执行没有差异 |
包容网关 | InclusiveGateway | 多分支条件同时满足的情况 |
事件
名称 | 节点名 | 说明 |
---|---|---|
开始事件 | StartEvent | 逻辑编排入口,仅一个 |
结束事件 | EndEvent | 结束节点,可多个 |
终止结束事件 | 流程或子流程实例强制结速 | |
信号捕获中间事件 | 监听信号(全局或进程实例内) | |
信号抛出中间事件 | 触发信号(全局或进程实例内) |
组件
名称 | 节点名 | 说明 |
---|---|---|
执行SQL | SQLTask | 编码、名称、入口、出口、跳过执行表达式 |
单表操作 | TableTask | |
接口调用 | APITask | |
脚本执行 | GroovyTask | |
内嵌子流程 | SubProcess | |
调用子流程 | CallActivity | |
事务子流程 | Transaction |
边界事件
名称 | 节点名 | 说明 |
---|---|---|
错误边界事件 | BoundaryEvent | 编码、名称、出口 |
逻辑编排场景分析
顺序执行场景
组件按顺序执行
null
分支场景
根据动作不同,可以转移到不同的状态
null
带条件的转移场景
动作发生后,根据转移条件,转移到不同的状态
null
退回场景1:使用不同状态标记退回数据
使用一个新状态来表示退回状态
null
退回场景2:使用相同状态标记退回数据
使用原状态,但用一个退回状态标记来表示退回状态
null
逻辑编排的使用
执行逻辑流
java
public static void start(String logicFlowCode, DelegateExecution execution)