也谈一下Activiti工作流节点的自由跳转

本文探讨了在openwebflow中实现工作流节点自由跳转遇到的问题,包括手动调用SqlSession可能遗漏的初始化操作、缺乏后退功能以及任务覆盖问题。作者通过分析源码,经历了多次尝试,发现直接数据库操作和使用taskService的不足,并指出Activiti的封装复杂,涉及过多的Command、事件、AtomicOperation和Listener。为了解决这些问题,作者选择自定义Command并交由CommandExecutor执行,最终成功实现安全的工作流节点跳转功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

安利一下国产化OpenWebFlow!!

https://github.com/bluejoe2008/openwebflow

 

OpenWebFlow是基于Activiti扩展的工作流引擎,它扩展的功能包括:

  • 完全接管了Activiti对活动(activity)权限的管理;
  • 完全接管了Activiti对用户表(IDENTITY_XXX表)的管理;
  • 允许运行时定义activity!彻底满足“中国特色”,并提供了安全的(同时也是优雅的)催办、代办、加签(包括前加签/后加签)、自由跳转(包括前进/后)、分裂节点等功能

最近在搞openwebflow的工作流节点自由跳转功能,在网上看了一些资料,感觉不是很好,总结原因如下:

 

  • 直接手动调用SqlSession的操作,感觉会漏掉一些重要的初始化操作(如:启动新节点之后加载其用户授权策略,等);
  • 只有往前(往已执行过的节点)跳转的功能,没有往后节点(往还没有执行的节点)跳转的功能;
  • 新任务不是追加到已有执行路径上,而是覆盖老任务;

 

那么就自己动手吧!操作流程其实也简单,大概如下:

 

  1. 按照目标节点(activity)定义创建一个新的任务(task),这个创建过程必须和正常流程到了某个节点的时候完全一样(如:不应该忽略用户授权策略的加载,任务名称表达式的计算,等);
  2. 删除掉当前任务(task);

 

注意:直接删除当前节点会报错,因为它还在流程之中,所以要先解除任务与当前执行execution的关联;

以上操作如何安全的实现呢?看了一下源码,经过多次痛苦的尝试,积累了不少教训:

 

  • 直接SqlSession操作数据库是不行的,这种方法容易擦枪走火!
  • 直接taskService.saveTask也是不行的,因为它实际上仅仅是针对DbSqlSession的操作!不commit一切操作都白搭!

 

那么怎么办呢?我想说的是,Activiti的封装做得很厚,想完全看懂是太难的。目前我还没想完全看懂,直接吐槽一下,与后人分享其中的痛苦࿱

### Activiti 工作流中并行回退解决方案 在处理 Activiti 工作流中的并行回退问题时,主要挑战在于如何正确清理所有分支任务以及确保主线流程能够正常继续执行。以下是针对该问题的具体分析和解决方案。 #### 1. 并行网关的工作机制 Activiti 的并行网关允许多个任务同时运行,在遇到回退需求时,如果仅清除当前分支的任务而未同步清理其他分支,则可能导致 `act_ru_task` 表中残留多余任务记录[^2]。这不仅会影响后续逻辑判断,还可能引发异常行为。 #### 2. 清理所有相关任务 为了防止上述情况发生,需采取措施彻底移除涉及的所有子任务实例。具体方法如下: - **获取当前活动节点 ID 和目标回退节点 ID** 使用 API 查询当前任务对应的节点信息及其父级流程实例状态。 - **暂停主线程以锁定资源** 调用命令模式接口(CommandExecutor),通过自定义 Command 实现事务控制下的批量更新操作[^1]。 ```java // 自定义 Command 示例代码片段 public class CustomTaskCleaner implements Command<Void> { private final String processInstanceId; public CustomTaskCleaner(String processInstanceId) { this.processInstanceId = processInstanceId; } @Override public Void execute(CommandContext commandContext) { TaskEntityManager taskManager = commandContext.getTaskEntityManager(); List<TaskEntity> tasks = taskManager.findTasksByProcessInstanceId(processInstanceId); for (TaskEntity task : tasks) { if (!task.isSuspended()) { // 确保不会影响已挂起的状态 task.delete("Parallel rollback cleanup"); } } return null; } } ``` - **重新设置历史路径标记** 修改流程变量或存储额外元数据来指示已完成的阶段已被重置,从而避免重复触发相同环节。 #### 3. 完成当前节点并向指定位置跳转 利用 Service Task 或 Script Task 执行脚本逻辑完成必要的前置条件准备之后再调用以下函数实现跳跃动作: ```java runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstanceId) .moveActivityIdTo(activityInstanceId, targetActivityId) .changeState(); ``` 以上步骤综合考虑了多线程环境下的并发安全性及持久化层交互细节,有效解决了因部分任务遗留所造成的功能性障碍。 ---
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值