蓝凌EKP18产品:流程引擎技术篇之原子操作

上一章我们学习了三种审批模式,知道了审批节点内部的多人处理策略,就是串行审批,并行审批,会审审批。这一次我们进行更深入的探讨,就是流程引擎的核心底层概念,就是原子操作。流程引擎驱动流程执行的最小基本操作。

一、什么是原子操作?

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 回退到父节点

核心认知:

  • 原子操作是流程引擎的"积木块"

  • 复杂流程 = 原子操作的编排组合

  • 上层的审批模式,最终通过底层原子操作实现