org.activiti.engine.delegate.ExecutionListener;
这个接口什么时候触发
org.activiti.engine.delegate.ExecutionListener是 Activiti 工作流引擎中用于监听执行实例(Execution)生命周期事件的接口。
触发时机
该接口在以下执行实例状态变化时触发:
| 事件类型 | 触发时机 |
|---|---|
start | 流程实例或执行分支开始时 |
end | 流程实例或执行分支结束时 |
take | 顺序流(Sequence Flow)被经过时 |
配置方式
1. 在 BPMN 流程定义中配置
xml
<process id="myProcess" name="My Process"> <!-- 在流程级别监听(流程全局级别作用范围) --> <extensionElements> <activiti:executionListener event="start" class="com.example.MyExecutionListener" /> <activiti:executionListener event="end" class="com.example.MyEndListener" /> </extensionElements> <!-- 在节点(Activity)级别监听 --> <userTask id="task1" name="审批任务"> <extensionElements> <activiti:executionListener event="start" class="com.example.TaskStartListener" /> <activiti:executionListener event="end" class="com.example.TaskEndListener" /> </extensionElements> </userTask> <!-- 在顺序流上监听(event 固定为 take) --> <sequenceFlow id="flow1" sourceRef="start" targetRef="task1"> <extensionElements> <activiti:executionListener event="take" class="com.example.FlowListener" /> </extensionElements> </sequenceFlow> </process>2. 使用表达式或委托表达式
xml
<!-- 使用表达式 --> <activiti:executionListener event="start" expression="${myBean.onStart(execution)}" /> <!-- 使用 Spring 委托表达式 --> <activiti:executionListener event="start" delegateExpression="${myExecutionListener}" />Java 实现示例
java
import org.activiti.engine.delegate.ExecutionListener; import org.activiti.engine.delegate.DelegateExecution; public class MyExecutionListener implements ExecutionListener { @Override public void notify(DelegateExecution execution) throws Exception { String eventName = execution.getEventName(); switch (eventName) { case "start": System.out.println("流程/节点开始,流程实例ID: " + execution.getProcessInstanceId()); // 可以设置流程变量 execution.setVariable("startTime", new Date()); break; case "end": System.out.println("流程/节点结束"); break; case "take": System.out.println("经过顺序流: " + execution.getCurrentTransitionId()); break; } } }与 TaskListener 的区别
表格
| 特性 | ExecutionListener | TaskListener |
|---|---|---|
| 监听对象 | 执行实例(Execution) | 用户任务(User Task) |
| 事件类型 | start,end,take | create,assignment,complete,delete |
| 适用场景 | 流程/节点/顺序流级别 | 任务级别(如任务创建、分配、完成) |
| 获取任务信息 | 无法直接获取 | 可以获取DelegateTask 对象(用户任务对象) |
典型应用场景
流程启动时初始化变量— 在流程
start事件中设置业务初始数据节点进入/离开时记录日志— 审计追踪
顺序流经过时做条件判断— 动态路由
流程结束时发送通知— 在流程
end事件中触发邮件/消息自动任务触发— 在 ServiceTask 的
start事件中执行业务逻辑
注意事项
execution参数包含当前执行上下文,可通过它获取/设置流程变量、流程实例ID 等监听器中抛出的异常会导致流程执行回滚
如果配置在顺序流上,event 必须是
take,不能是start或end
TaskListener必须嫁接挂载到UserTask任务类型对象上才能起到作用
任务事件监听器TaskListener就是基于UserTask用户任务对象存活的,它必须与UserTask绑定,它的功能就是监听用户任务UserTask对象在流程中的事件状态,所以TaskListener需要绑定到UserTask上去使用,这个绑定过程可以在.BPMN流程定义文件中通过标签元素来书写(声明式定义)
————————————————
TaskListener是 Activiti/Flowable 工作流引擎中用于监听用户任务(User Task)生命周期事件的接口。它与ExecutionListener不同,专门处理任务级别的状态变化。
java
package org.activiti.engine.delegate; public interface TaskListener { // 事件类型常量 String EVENTNAME_CREATE = "create"; // 任务创建事件 String EVENTNAME_ASSIGNMENT = "assignment"; // 任务分配事件(分配给人) String EVENTNAME_COMPLETE = "complete"; // 任务完成事件 String EVENTNAME_DELETE = "delete"; // 任务删除事件 String EVENTNAME_ALL_EVENTS = "all"; // 所有事件(部分版本支持) void notify(DelegateTask delegateTask);//事件处理回调方法 }与 ExecutionListener 的核心区别
表格
| 特性 | TaskListener | ExecutionListener |
|---|---|---|
| 监听对象 | 用户任务(User Task) | 执行实例(Execution) |
| 参数类型 | DelegateTask(UserTask的顶级父接口) | DelegateExecution(Execution的顶级父接口) |
| 事件类型 | create, assignment, complete, delete | start, end, take |
| 配置位置及作用域 | 用户任务节点内 | 流程/节点/顺序流 |
| 获取任务信息 | ✅ 任务办理人、候选人等 | ❌ 无任务概念 |
| 设置任务变量 | ✅ 支持 | ✅ 支持 |
使用方式
方式一:BPMN XML 中配置(最常用)
xml
复制
<userTask id="approveTask" name="经理审批"> <extensionElements> <!-- 任务创建时触发 --> <activiti:taskListener event="create" class="com.example.listener.TaskCreateListener" /> <!-- 任务分配时触发 --> <activiti:taskListener event="assignment" class="com.example.listener.TaskAssignListener" /> <!-- 任务完成时触发 --> <activiti:taskListener event="complete" class="com.example.listener.TaskCompleteListener" /> <!-- 任务删除时触发 --> <activiti:taskListener event="delete" class="com.example.listener.TaskDeleteListener" /> </extensionElements> </userTask>方式二:使用表达式(Expression)方式
xml
<userTask id="task1" name="审批"> <extensionElements> <!-- 调用 Spring Bean 的方法 --> <activiti:taskListener event="create" expression="${taskHandler.onCreate(task)}" /> <!-- 使用委托表达式 --> <activiti:taskListener event="complete" delegateExpression="${myTaskListener}" /> </extensionElements> </userTask>方式三:Java 代码动态添加
java
// 获取任务服务 TaskService taskService = processEngine.getTaskService(); // 查询任务 Task task = taskService.createTaskQuery() .taskId("taskId") .singleResult(); // 动态添加监听器(较少使用,通常静态配置) // 注意:Activiti 原生不支持运行时动态添加,Flowable工作流框架部分支持完整 Java 实现示例
1. 任务创建监听器(自动设置候选人/发送通知)
java
import org.activiti.engine.delegate.TaskListener; import org.activiti.engine.delegate.DelegateTask; import org.springframework.stereotype.Component; public class TaskCreateListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { // 获取任务信息 String taskId = delegateTask.getId(); String taskName = delegateTask.getName(); String processInstanceId = delegateTask.getProcessInstanceId(); String executionId = delegateTask.getExecutionId(); System.out.println("任务创建: " + taskName + " [ID=" + taskId + "]"); // 1. 动态设置候选人(如果流程变量中有部门信息) String deptId = (String) delegateTask.getVariable("deptId"); if ("sales".equals(deptId)) { delegateTask.addCandidateGroup("sales_manager"); // 添加候选组 } else { delegateTask.addCandidateGroup("general_manager"); } // 2. 设置任务到期时间(T+3天) Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, 3); delegateTask.setDueDate(cal.getTime()); // 3. 设置优先级 delegateTask.setPriority(50); // 4. 发送待办通知(调用消息服务) // sendNotification(delegateTask); } }2. 任务分配监听器(记录分配日志)
java
public class TaskAssignListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { String assignee = delegateTask.getAssignee(); String taskName = delegateTask.getName(); System.out.println("任务分配: " + taskName + " -> " + assignee); // 记录分配历史到自定义表 // 或发送邮件/短信通知办理人 } }3. 任务完成监听器(校验/记录)
java
public class TaskCompleteListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { String taskId = delegateTask.getId(); String assignee = delegateTask.getAssignee(); // 获取任务完成时填写的表单数据(任务及流程变量的载体) Map<String, Object> variables = delegateTask.getVariables(); String approveResult = (String) variables.get("approveResult"); System.out.println("任务完成: " + taskId + " 由 " + assignee + " 完成"); System.out.println("审批结果: " + approveResult); // 1. 校验必填变量 if (approveResult == null) { throw new RuntimeException("审批结果不能为空!"); } // 2. 根据审批结果设置流程变量 if ("reject".equals(approveResult)) { delegateTask.setVariable("needReSubmit", true); } // 3. 记录操作日志到审计表 // auditLogService.record(delegateTask); } }4. 任务删除监听器(清理工作)
java
public class TaskDeleteListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { System.out.println("任务删除: " + delegateTask.getName()); // 清理相关资源 // 取消定时提醒等 } }事件触发顺序详解
假设一个用户任务从创建到完成的完整流程:
流程到达 UserTask ↓ ExecutionListener "start" 触发(如果有) ↓ TaskListener "create" 触发 ← 任务实例创建 ↓ TaskListener "assignment" 触发 ← 设置办理人/候选人时 ↓ 用户完成任务(taskService.complete) ↓ TaskListener "complete" 触发 ← 任务完成前 ↓ ExecutionListener "end" 触发(如果有) ↓ 流程继续流转Spring 集成配置(推荐)
@Component("myTaskListener") public class SpringTaskListener implements TaskListener { @Autowired private NotificationService notificationService; @Autowired private AuditLogService auditLogService; @Override public void notify(DelegateTask delegateTask) { String eventName = delegateTask.getEventName(); switch (eventName) { case "create": // 发送待办通知 notificationService.sendTodo(delegateTask); break; case "assignment": // 记录分配 auditLogService.logAssign(delegateTask); break; case "complete": // 记录完成 auditLogService.logComplete(delegateTask); break; } } }BPMN 中引用:
xml
<activiti:taskListener event="create" delegateExpression="${myTaskListener}" />Flowable 与 Activiti 的差异
表格
复制
| 特性 | Activiti 5/6 | Flowable 6+ |
|---|---|---|
| 包路径 | org.activiti... | org.flowable... |
| 额外事件 | 无 | timeout(任务超时) |
| 子任务监听 | 有限支持 | 更完善 |
Flowable 的timeout事件示例:
xml
复制
<flowable:taskListener event="timeout" class="com.example.TimeoutHandler" />常见应用场景
表格
复制
| 场景 | 使用事件 | 实现 |
|---|---|---|
| 自动分配办理人 | create | 根据业务规则动态设置assignee |
| 发送待办邮件 | create/assignment | 调用邮件服务 |
| 记录操作日志 | complete | 写入审计表 |
| 任务超时提醒 | timeout(Flowable) | 定时任务处理 |
| 任务转办记录 | assignment | 记录转办历史 |
| 完成前校验 | complete | 校验表单数据完整性 |
DelegateTask API 与监听器
一、DelegateTask 完整 API 列表
java
// ==================== 任务基本信息 ==================== String getId(); // 任务唯一ID String getName(); // 任务名称 void setName(String name); // 动态修改任务名称 String getDescription(); // 任务描述 void setDescription(String description); // 设置描述 String getAssignee(); // 当前办理人 void setAssignee(String assignee); // 设置办理人(直接指派) String getOwner(); // 任务所有者 void setOwner(String owner); // 设置所有者 Date getCreateTime(); // 创建时间 Date getDueDate(); // 到期时间 void setDueDate(Date dueDate); // 设置到期时间 int getPriority(); // 优先级(默认50) void setPriority(int priority); // 设置优先级 String getTaskDefinitionKey(); // 任务定义Key(BPMN中的id) String getFormKey(); // 表单Key // ==================== 候选人/候选组管理 ==================== void addCandidateUser(String userId); // 添加候选用户 void addCandidateGroup(String groupId); // 添加候选组 void deleteCandidateUser(String userId); // 删除候选用户 void deleteCandidateGroup(String groupId); // 删除候选组 Set<IdentityLink> getCandidates(); // 获取所有候选人/组 // ==================== 流程关联信息 ==================== String getExecutionId(); // 执行实例ID String getProcessInstanceId(); // 流程实例ID String getProcessDefinitionId(); // 流程定义ID String getProcessDefinitionKey(); // 流程定义Key String getEventName(); // 当前触发的事件名(create/assignment/complete/delete) // ==================== 变量操作 ==================== Object getVariable(String variableName); <T> T getVariable(String variableName, Class<T> variableClass); Map<String, Object> getVariables(); // 获取所有流程变量 Map<String, Object> getVariablesLocal(); // 获取本地变量 void setVariable(String variableName, Object value); void setVariableLocal(String variableName, Object value); // 仅当前任务可见 void setVariables(Map<String, Object> variables); void setVariablesLocal(Map<String, Object> variables); boolean hasVariable(String variableName); void removeVariable(String variableName); void removeVariableLocal(String variableName); // ==================== 委托/代理相关 ==================== DelegationState getDelegationState(); // 委托状态:PENDING/RESOLVED void setDelegationState(DelegationState delegationState); // ==================== 其他 ==================== String getCategory(); // 任务分类 void setCategory(String category); // 设置分类 DelegateExecution getExecution(); // 获取关联的 Execution 对象二、TaskListener 与 ExecutionListener 配合使用
触发顺序(关键)
当一个流程到达UserTask节点时,事件触发顺序如下:
流程流转到达 UserTask 节点 │ ▼ ┌─────────────────────────────────────┐ │ ExecutionListener event="start" │ ← 第1触发:执行实例进入节点 │ (节点级别的 ExecutionListener) │ └─────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ TaskListener event="create" │ ← 第2触发:任务实例创建 │ (此时任务已存在,但可能未分配人) │ └─────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ TaskListener event="assignment" │ ← 第3触发:设置办理人/候选人时 │ (如果创建时就指定了assignee, │ │ 则 create 之后立即触发 assignment)│ └─────────────────────────────────────┘ │ ▼ 用户处理任务中... │ ▼ 用户调用 taskService.complete() ┌─────────────────────────────────────┐ │ TaskListener event="complete" │ ← 第4触发:任务完成前 │ (此时任务还未销毁,变量可读写) │ └─────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────┐ │ ExecutionListener event="end" │ ← 第5触发:执行实例离开节点 │ (节点级别的 ExecutionListener) │ └─────────────────────────────────────┘ │ ▼ 流程继续向下流转(SequenceFlow 的 take 事件)完整 BPMN 配合示例
xml
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="http://example.org/leave"> <process id="leaveApproval" name="请假审批流程"> <startEvent id="start" name="开始" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="applyTask" /> <!-- 申请人填写 --> <userTask id="applyTask" name="填写请假单"> <extensionElements> <activiti:executionListener event="start" class="com.example.listener.ApplyExecutionStartListener" /> <activiti:taskListener event="create" class="com.example.listener.ApplyTaskCreateListener" /> <activiti:taskListener event="complete" class="com.example.listener.ApplyTaskCompleteListener" /> <activiti:executionListener event="end" class="com.example.listener.ApplyExecutionEndListener" /> </extensionElements> </userTask> <sequenceFlow id="flow2" sourceRef="applyTask" targetRef="managerTask" /> <!-- 经理审批 --> <userTask id="managerTask" name="经理审批"> <extensionElements> <activiti:executionListener event="start" class="com.example.listener.ManagerExecutionStartListener" /> <activiti:taskListener event="create" class="com.example.listener.ManagerTaskCreateListener" /> <activiti:taskListener event="assignment" class="com.example.listener.ManagerTaskAssignListener" /> <activiti:taskListener event="complete" class="com.example.listener.ManagerTaskCompleteListener" /> <activiti:executionListener event="end" class="com.example.listener.ManagerExecutionEndListener" /> </extensionElements> </userTask> <sequenceFlow id="flow3" sourceRef="managerTask" targetRef="end" /> <endEvent id="end" name="结束" /> </process> </definitions>Java 实现:各监听器分工协作
java
// ============================================ // 1. 节点进入时的 ExecutionListener(start) // 职责:初始化节点级上下文,设置节点变量 // ============================================ public class ManagerExecutionStartListener implements ExecutionListener { @Override public void notify(DelegateExecution execution) { System.out.println("[ExecutionListener:start] 进入经理审批节点"); System.out.println(" → ExecutionId: " + execution.getId()); // 设置节点级变量(Execution 级别,对该执行实例下的所有任务可见) execution.setVariable("enterManagerNodeTime", new Date()); execution.setVariable("currentNode", "managerTask"); } } // ============================================ // 2. 任务创建时的 TaskListener(create) // 职责:动态设置候选人、到期时间、优先级 // ============================================ public class ManagerTaskCreateListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { System.out.println("[TaskListener:create] 经理审批任务已创建"); System.out.println(" → TaskId: " + delegateTask.getId()); // 从流程变量中获取申请人部门 String dept = (String) delegateTask.getVariable("applyDept"); // 根据部门动态设置候选审批组 if ("tech".equals(dept)) { delegateTask.addCandidateGroup("tech_manager"); } else { delegateTask.addCandidateGroup("general_manager"); } // 设置任务2天内必须处理 Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, 2); delegateTask.setDueDate(cal.getTime()); // 设置高优先级(请假审批紧急) delegateTask.setPriority(80); } } // ============================================ // 3. 任务分配时的 TaskListener(assignment) // 职责:通知具体的办理人 // ============================================ public class ManagerTaskAssignListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { String assignee = delegateTask.getAssignee(); String taskName = delegateTask.getName(); System.out.println("[TaskListener:assignment] 任务已分配给: " + assignee); // 发送邮件/钉钉/企业微信通知 // notificationService.sendToUser(assignee, "您有新的待办任务: " + taskName); } } // ============================================ // 4. 任务完成时的 TaskListener(complete) // 职责:校验表单、记录审批意见、设置后续变量 // ============================================ public class ManagerTaskCompleteListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { String assignee = delegateTask.getAssignee(); // 获取用户提交的任务变量(complete时传入的变量) Boolean approved = (Boolean) delegateTask.getVariable("approved"); String comment = (String) delegateTask.getVariable("comment"); System.out.println("[TaskListener:complete] " + assignee + " 完成任务"); System.out.println(" → 审批结果: " + (approved ? "同意" : "拒绝")); System.out.println(" → 审批意见: " + comment); // 校验:必须填写审批意见 if (comment == null || comment.trim().isEmpty()) { throw new RuntimeException("审批意见不能为空!"); } // 设置流程变量供后续节点使用 delegateTask.setVariable("managerApproved", approved); delegateTask.setVariable("managerComment", comment); delegateTask.setVariable("managerCompleteTime", new Date()); } } // ============================================ // 5. 节点离开时的 ExecutionListener(end) // 职责:清理节点级资源,记录节点耗时 // ============================================ public class ManagerExecutionEndListener implements ExecutionListener { @Override public void notify(DelegateExecution execution) { Date enterTime = (Date) execution.getVariable("enterManagerNodeTime"); long duration = System.currentTimeMillis() - enterTime.getTime(); System.out.println("[ExecutionListener:end] 离开经理审批节点"); System.out.println(" → 节点耗时: " + duration + "ms"); // 记录到审计表 // auditService.recordNodeDuration(execution.getProcessInstanceId(), "managerTask", duration); } }控制台输出示例
plain
复制
[ExecutionListener:start] 进入经理审批节点 → ExecutionId: 2501 [TaskListener:create] 经理审批任务已创建 → TaskId: 2504 [TaskListener:assignment] 任务已分配给: zhangsan [TaskListener:complete] zhangsan 完成任务 → 审批结果: 同意 → 审批意见: 同意请假,注意交接工作 [ExecutionListener:end] 离开经理审批节点 → 节点耗时: 3600000ms两者配合使用的设计建议
表格
复制
| 职责 | 使用 ExecutionListener | 使用 TaskListener |
|---|---|---|
| 节点级变量初始化 | ✅start | ❌ |
| 任务候选人/组设置 | ❌ | ✅create |
| 任务到期时间/优先级 | ❌ | ✅create |
| 发送待办通知给具体人 | ❌ | ✅assignment |
| 表单数据校验 | ❌ | ✅complete |
| 记录操作日志 | ✅end | ✅complete |
| 节点耗时统计 | ✅start+end | ❌ |
| 流程变量传递 | ✅ | ✅ |
核心原则:与任务办理人相关的操作(分配、通知、表单)用TaskListener;与节点执行逻辑相关的(初始化、统计、清理)用ExecutionListener。
————————————————————
篇外话题
DelegateTask是一个接口(interface),不是类。
具体定义
Activiti(5.x / 6.x)
java
复制
package org.activiti.engine.delegate; public interface DelegateTask extends org.activiti.engine.task.Task { // 额外的方法:setAssignee, setOwner, setDueDate, setPriority 等 // 以及变量操作相关方法 }Flowable(6.x+)
java
复制
package org.flowable.engine.delegate; public interface DelegateTask extends org.flowable.task.api.Task { // 类似的方法扩展 }为什么设计成接口?
引擎内部实现:Activiti/Flowable 引擎内部有具体的实现类(如
TaskEntity),但对外暴露的是DelegateTask接口,隐藏内部实现细节。解耦:你在写
javaTaskListener时,只需要面向接口编程:public class MyListener implements TaskListener { @Override public void notify(DelegateTask delegateTask) { // 参数类型是接口 delegateTask.setAssignee("zhangsan"); } }实际运行时,引擎传入的是内部实现类的实例。
扩展性:接口可以方便地在不同版本间扩展,而不破坏用户代码。
继承关系
plain
复制
Task (接口,定义基础getter) ↑ DelegateTask (接口,扩展setter和变量操作) ↑ TaskEntity (引擎内部实现类,用户不直接使用)所以你在TaskListener中接收到的delegateTask参数,实际类型是引擎内部的实现类,但你在代码中只能看到接口定义的方法。