实战Activity工作流:解锁复杂业务场景的自动化编排之道

张开发
2026/4/15 6:06:26 15 分钟阅读

分享文章

实战Activity工作流:解锁复杂业务场景的自动化编排之道
1. 从零认识Activity工作流引擎第一次接触Activity工作流引擎时我正被一个复杂的审批系统折磨得焦头烂额。当时项目需要实现一个跨部门协作的立项审批流程涉及市场部、技术部、财务部等多个部门的会签。如果用传统硬编码方式实现光是处理各种并行审批和条件分支就写了近千行代码后期维护简直是一场噩梦。Activity就像是为这类场景量身定制的解决方案。它本质上是一个业务流程的自动化执行引擎基于BPMN 2.0标准把复杂的业务流程转化为可视化的流程图。想象一下你只需要用标准图形元素画出流程图剩下的流转、分支、并行处理等复杂逻辑都交给引擎自动完成。举个真实案例去年我们重构的电商订单系统使用Activity后订单取消流程的开发周期从2周缩短到3天流程变更时只需修改BPMN图无需重新部署代码历史流程查询功能实现成本降低80%2. 项目立项审批实战案例2.1 业务流程拆解让我们以项目立项审批这个典型场景为例。完整流程包括项目经理提交立项申请并行会签技术部评估可行性、市场部评估收益、财务部审核预算根据会签结果决策全部通过则进入执行阶段任一部门否决则进入申诉流程超时自动提醒任何环节超过3天未处理触发提醒这个流程完美展示了Activity最擅长的三种复杂场景并行网关处理多部门同时会签包含网关根据会签结果选择不同路径边界事件处理审批超时情况2.2 BPMN流程图设计用Activity实现这个流程首先需要设计BPMN图。关键节点包括process idprojectApproval name项目立项审批流程 !-- 开始事件 -- startEvent idstartEvent extensionElements activiti:formProperty idprojectName name项目名称 typestring requiredtrue/ /extensionElements /startEvent !-- 项目经理提交 -- userTask idsubmitTask name提交立项申请 activiti:assignee${projectManager} extensionElements activiti:formProperty idbusinessCase name商业论证 typestring/ /extensionElements /userTask !-- 并行会签网关 -- parallelGateway idparallelGateway name会签分支/ !-- 部门审批任务 -- userTask idtechReview name技术可行性评估 activiti:assignee${techLead}/ userTask idmarketReview name市场收益评估 activiti:assignee${marketManager}/ userTask idfinanceReview name预算审核 activiti:assignee${financeManager}/ !-- 并行汇聚网关 -- parallelGateway idjoinGateway name会签结果汇聚/ !-- 包含网关决策 -- inclusiveGateway iddecisionGateway name审批结果决策/ !-- 边界事件 -- boundaryEvent idtimeoutEvent attachedToReftechReview timerEventDefinition timeDurationPT72H/timeDuration /timerEventDefinition /boundaryEvent /process2.3 核心代码实现部署流程定义// Spring Boot环境下自动配置的ProcessEngine Autowired private RepositoryService repositoryService; public String deployProcess() { Deployment deployment repositoryService.createDeployment() .addClasspathResource(processes/project-approval.bpmn20.xml) .name(项目立项审批流程) .deploy(); return deployment.getId(); }启动流程实例Autowired private RuntimeService runtimeService; public ProcessInstance startProcess(String projectId, String projectManager) { MapString, Object variables new HashMap(); variables.put(projectId, projectId); variables.put(projectManager, projectManager); variables.put(techLead, tech_leader_1); variables.put(marketManager, market_manager_1); variables.put(financeManager, finance_manager_1); return runtimeService.startProcessInstanceByKey( projectApproval, projectId, variables ); }处理会签任务Autowired private TaskService taskService; public void completeTechReview(String taskId, boolean approved, String comments) { MapString, Object variables new HashMap(); variables.put(techApproved, approved); variables.put(techComments, comments); taskService.complete(taskId, variables); }3. 高级特性深度应用3.1 动态任务分配实际项目中审批人往往需要动态确定。Activity提供了灵活的分配策略// 在流程启动时动态设置审批人 variables.put(techLead, userService.findTechLead(project.getDepartment())); // 或者通过任务监听器动态分配 public class DynamicAssignmentListener implements TaskListener { Override public void notify(DelegateTask task) { String department (String) task.getVariable(department); if (techReview.equals(task.getTaskDefinitionKey())) { task.setAssignee(userService.findTechLead(department)); } } }3.2 超时自动提醒配置边界事件实现超时处理boundaryEvent idtimeoutEvent attachedToReftechReview timerEventDefinition timeDurationPT72H/timeDuration /timerEventDefinition /boundaryEvent sequenceFlow sourceReftimeoutEvent targetRefsendReminder/ serviceTask idsendReminder activiti:classcom.example.SendReminderTask/对应的Java实现public class SendReminderTask implements JavaDelegate { Autowired private NotificationService notificationService; Override public void execute(DelegateExecution execution) { String assignee (String) execution.getVariable(techLead); String taskName 技术可行性评估; notificationService.sendReminder(assignee, taskName); } }3.3 会签结果聚合处理并行会签结果时需要聚合多个部门的审批意见public void makeFinalDecision(String processInstanceId) { boolean techApproved (boolean) runtimeService.getVariable(processInstanceId, techApproved); boolean marketApproved (boolean) runtimeService.getVariable(processInstanceId, marketApproved); boolean financeApproved (boolean) runtimeService.getVariable(processInstanceId, financeApproved); if (techApproved marketApproved financeApproved) { runtimeService.setVariable(processInstanceId, finalDecision, APPROVED); } else { runtimeService.setVariable(processInstanceId, finalDecision, REJECTED); } }4. 生产环境最佳实践4.1 性能优化方案在高并发场景下我们总结了这些优化经验流程定义缓存配置流程定义缓存大小activiti.process-definition-cache-limit100异步执行器处理耗时操作serviceTask idarchiveTask activiti:asynctrue activiti:classcom.example.ArchiveProjectTask/批量操作减少数据库交互// 批量查询任务 ListTask tasks taskService.createTaskQuery() .taskAssignee(userId) .listPage(0, 100); // 批量完成任务 tasks.forEach(task - { taskService.complete(task.getId()); });4.2 监控与运维完善的监控体系包括流程实例监控跟踪运行中的流程long runningCount runtimeService.createProcessInstanceQuery() .processDefinitionKey(projectApproval) .count();性能指标收集统计任务处理时间HistoricTaskInstance historicTask historyService.createHistoricTaskInstanceQuery() .taskId(taskId) .singleResult(); long duration historicTask.getDurationInMillis();异常处理机制自动重试失败的任务ListJob failedJobs managementService.createJobQuery() .withException() .list(); failedJobs.forEach(job - { managementService.moveJobToDeadLetterJob(job.getId()); });4.3 常见问题解决方案问题1会签任务卡住怎么办检查并行网关的进出规则是否匹配确认所有分支都正确调用了taskService.complete()问题2流程变量丢失检查变量作用域流程实例级 vs 任务级使用runtimeService.setVariable()替代临时变量问题3历史数据膨胀配置历史清理策略activiti.history-levelaudit activiti.history-cleanup-enabledtrue

更多文章