上一章我们学习了三种审批模式,知道了审批节点内部的多人处理策略,就是串行审批,并行审批,会审审批。这一次我们进行更深入的探讨,就是流程引擎的核心底层概念,就是原子操作。流程引擎驱动流程执行的最小基本操作。
一、什么是原子操作?
1.1 定义
**原子操作(Atomic Operation)**是流程引擎中最小的、不可分割的执行单元。
1.2 类比理解
原子操作就像乐高积木的基本块:
乐高积木 vs 原子操作
──────────────────────────────
基本块 最小执行单元
拼成一个模型 组合成完整流程
无法再拆分的块 无法再分割的操作
1.3 为什么需要原子操作?
复杂的流程执行 = 拆解 + 组合
┌─────────────────────────────────────────┐
│ 复杂流程:张三审批通过 │
├─────────────────────────────────────────┤
│ 1. 更新工作项状态 │
│ 2. 记录审批意见 │
│ 3. 检查串行审批是否还有人 │
│ 4. 流转到下一个节点 │
│ 5. 创建下一个工作项 │
│ 6. 发送通知 │
│ ... │
└─────────────────────────────────────────┘
↓ 拆解
┌─────────────────────────────────────────┐
│ 原子操作列表 │
├─────────────────────────────────────────┤
│ · ExecuteTask (执行任务) │
│ · TransitionStartTask (启动下一任务) │
│ · TransitionEndTask (结束当前任务) │
│ · AbandonTask (废弃任务) │
│ · JumpToNextActivity (跳转到节点) │
│ ... │
└─────────────────────────────────────────┘
二、原子操作接口
2.1 接口定义
// AtomicOperation.java ------ 原子操作接口
public interface AtomicOperation {
/** 启动任务操作 */
String TRANSITION_START_TASK = "TransitionStartTask";
/** 执行任务操作 */
String EXECUTE_TASK = "ExecuteTask";
/** 结束任务操作 */
String TRANSITION_END_TASK = "TransitionEndTask";
/**
* 执行操作
* @param execution 执行上下文
*/
void propagate(ExecutionWraper execution);
/**
* 是否允许重复执行
*/
boolean allowRepeat();
}
2.2 核心方法解读
| 方法 | 作用 |
|---|---|
propagate(ExecutionWraper) |
执行原子操作,接收执行上下文作为输入 |
allowRepeat() |
是否允许重复执行,防重复处理 |
三、EKP 中的原子操作类型
3.1 完整操作列表
AtomicOperation 接口
│
┌──────────┬───────────┼───────────┬──────────┬──────────────┐
↓ ↓ ↓ ↓ ↓ ↓
ExecuteTask Transition Transition Abandon JumpToNext MoveToParent
StartTask EndTask Task Activity Task
↑ ↑
启动任务 结束任务
3.2 各操作详解
1. ExecuteTask ------ 执行任务
// ExecuteTask.java ------ 执行任务操作
public class ExecuteTask implements AtomicOperation {
@Override
public void propagate(ExecutionWraper execution) {
// 获取节点行为
ActivityBehaviour behaviour = execution.getBehaviour();
try {
// 执行节点逻辑(审批、自动计算等)
behaviour.execute(execution);
} catch (Exception ex) {
throw new WorkflowRuntimeException("执行任务时出错", ex);
}
// 如果节点执行完毕,触发结束操作
if (execution.isEnded()) {
execution.abandonChildren();
execution.performAtomicOperation(TRANSITION_END_TASK);
}
}
@Override
public boolean allowRepeat() {
return false; // 不允许重复执行
}
}
作用:执行节点的业务逻辑,如审批、自动节点计算等。
2. TransitionStartTask ------ 启动下一任务
// TransitionStartTask.java ------ 启动任务操作
public class TransitionStartTask implements AtomicOperation {
@Override
public void propagate(ExecutionWraper execution) {
// 获取流转连线
Transition transition = execution.getTransition();
Activity source = transition.getSource();
// 设置执行状态为激活
execution.setFdState(Execution.STATE_ACTIVE);
// 指向目标任务节点
execution.setActivity(source);
// 触发任务进入事件,并执行任务
execution.fire(new EnterTaskEvent(), execution.getTask(),
new ActivateTask());
}
@Override
public boolean allowRepeat() {
return false;
}
}
作用:将流程流转到下一个节点,启动下一个任务。
3. TransitionEndTask ------ 结束当前任务
// TransitionEndTask.java ------ 结束任务操作
public class TransitionEndTask implements AtomicOperation {
@Override
public void propagate(ExecutionWraper execution) {
// 确定下一步路由:下一节点 / 跳转 / 回父节点 / 结束流程
NextRoute route = getNextRoute(execution);
// 如果是预检模式(prepare),直接流转
if (execution.getMode() == Mode.PREPARESTATEMENT) {
execution.setFdState(Execution.STATE_ENDED);
nextOperation.propagate(execution);
} else {
// 触发任务结束事件
execution.setEnded();
execution.fire(new EndedTaskEvent(route.destination),
execution.getTask(), nextOperation);
}
}
}
作用:结束当前任务,确定流转方向(下一节点/跳转/回父节点/结束)。
4. AbandonTask ------ 废弃任务
// AbandonTask.java ------ 废弃任务操作
public class AbandonTask implements SyncAtomicOperation {
private boolean includeSelf; // 是否废弃自身
private boolean destoryScope; // 是否删除执行路径
@Override
public void propagate(ExecutionWraper execution) {
// 递归废弃所有子执行路径
deepAbandon(execution, includeSelf);
// 如果包含自身,执行废弃
if (includeSelf) {
abandon(execution, destoryScope);
}
}
@Override
public boolean allowRepeat() {
return true; // 可以重复执行
}
}
作用:废弃当前执行路径及其子路径,用于驳回、废弃等场景。
5. JumpToNextActivity ------ 跳转到节点
// JumpToNextActivity.java ------ 跳转到节点操作
public class JumpToNextActivity implements AtomicOperation {
@Override
public void propagate(ExecutionWraper execution) {
// 废弃当前并发路径(如果需要)
abandonCurrentConcurrentIfRequired(execution);
// 获取下一个执行路径
ExecutionWraper propagate = getNextExecution(execution);
// 设置目标节点
propagate.setActivity(destination);
propagate.setTransition(new TransitionWraper(destination, null));
// 启动目标节点任务
propagate.performAtomicOperation(TRANSITION_START_TASK);
}
}
作用:特权跳转,跳过中间节点直接到目标节点。
四、原子操作的执行模型
4.1 基本模型
输入 (ExecutionWraper) → [原子操作] → 输出 / 触发下一个原子操作
4.2 ExecutionWraper ------ 执行上下文
// ExecutionWraper 包含的信息
public class ExecutionWraper {
Execution processInstance; // 流程实例
Task task; // 当前任务
Activity activity; // 当前节点
Transition transition; // 流转连线
String mode; // 执行模式
// ... 其他上下文信息
}
4.3 原子操作的链式执行
用户提交审批
↓
┌─────────────────────────────────────────────────────────┐
│ 1. ExecuteTask │
│ · 执行审批逻辑 │
│ · 检查审批模式(串行/并行/会审) │
│ ↓ │
│ 2. TransitionEndTask │
│ · 确定下一节点 │
│ · 触发任务结束事件 │
│ ↓ │
│ 3. TransitionStartTask │
│ · 设置目标节点 │
│ · 触发任务开始事件 │
│ ↓ │
│ 4. ExecuteTask │
│ · 执行下一节点的逻辑 │
│ · 创建工作项(如果需要) │
└─────────────────────────────────────────────────────────┘
五、原子操作的组合示例
5.1 审批通过场景
场景:张三完成审批,流程流转到李四
原子操作序列:
┌─────────────────────────────────────────────────────┐
│ 1. ExecuteTask │
│ · 检查审批模式 │
│ · 更新工作项状态为"完成" │
│ · 记录审批意见 │
│ ↓ │
│ 2. TransitionEndTask │
│ · 获取下一个节点(李四审批) │
│ · 确定流转路由 │
│ ↓ │
│ 3. TransitionStartTask │
│ · 激活李四审批节点 │
│ ↓ │
│ 4. ExecuteTask │
│ · 创建李四的工作项 │
│ · 发送通知 │
└─────────────────────────────────────────────────────┘
5.2 驳回场景
场景:李四驳回申请,退回给张三
原子操作序列:
┌─────────────────────────────────────────────────────┐
│ 1. ExecuteTask │
│ · 执行驳回逻辑 │
│ · 记录驳回原因 │
│ ↓ │
│ 2. AbandonTask │
│ · 废弃当前任务 │
│ ↓ │
│ 3. JumpToNextActivity / MoveToParentTask │
│ · 跳转到退回节点 │
│ ↓ │
│ 4. TransitionStartTask │
│ · 激活张三的任务节点 │
│ ↓ │
│ 5. ExecuteTask │
│ · 创建/恢复张三的工作项 │
└─────────────────────────────────────────────────────┘
六、原子操作的特性
6.1 不可分割性
原子操作是最小执行单元,不会被中途打断:
张三审批通过 → 不会被拆分 → 整个操作要么全部完成,要么全部失败
6.2 可组合性
复杂流程 = 原子操作的编排组合
串行组合:Op1 → Op2 → Op3
并行组合:Op1 ─┬─→ Result
├─→ Result
└─→ Result
条件组合:if (condition) Op1 else Op2
复杂流程 = 原子操作的编排组合
6.3 防重复机制
@Override
public boolean allowRepeat() {
return false; // 或 return true
}
| 返回值 | 含义 | 使用场景 |
|---|---|---|
false |
不允许重复 | 结束任务、启动任务 |
true |
允许重复 | 废弃任务、事件处理 |
七、原子操作与上节课的关系
上节课:审批模式决定了"多人如何审批"
串行:fdHandler 依次变更 → TransitionEndTask 流转到同节点
并行:任意一人完成 → TransitionEndTask 流转到下一节点
会审:所有人完成 → TransitionEndTask 流转到下一节点
这节课:原子操作决定了"如何执行流转"
ExecuteTask → TransitionEndTask → TransitionStartTask
(执行) → (结束当前) → (启动下一个)
八、总结
| 原子操作 | 作用 | 能否重复 |
|---|---|---|
| ExecuteTask | 执行节点逻辑 | 否 |
| TransitionStartTask | 启动下一任务 | 否 |
| TransitionEndTask | 结束当前任务 | 否 |
| AbandonTask | 废弃任务 | 能 |
| JumpToNextActivity | 跳转节点 | 能 |
| MoveToParentTask | 回退到父节点 | 能 |
核心认知:
原子操作是流程引擎的"积木块"
复杂流程 = 原子操作的编排组合
上层的审批模式,最终通过底层原子操作实现