Activiti之任务监听器与执行监听器详解

946 阅读4分钟

关于任务监听器与执行监听器

在 Activiti 工作流引擎中,任务监听器(Task Listener)和执行监听器(Execution Listener)是两种常用的监听器类型,用于在流程的不同阶段添加自定义逻辑。它们可以在流程定义中配置,以便在特定事件发生时触发预定义的操作。比如,动态分配节点处理人。通过前一个节点设置的变量,在运行到下一个节点时设置对应的处理人; 当流程运行到某个节点时,发送邮件或短信给待办用户;统计流程处理时长,是否超时等;业务层面数据处理。

任务监听器

任务监听器是一种允许你在任务生命周期内的不同事件上执行操作的机制。每当一个与任务相关的事件发生时,任务监听器可以被触发,以便在任务开始、分配、完成等阶段执行特定的逻辑。

activiti的源码中,任务监听器事件包括:

image.png

  • create:在任务被创建时触发。
  • assignment:在任务被分配给用户或组时触发。
  • complete:在任务完成时触发。
  • delete:经测试会在任务完成时触发。

可以通过配置任务监听器来执行以下类型的操作:

  • 分配任务给特定用户或用户组。
  • 更新任务属性,如优先级、截止日期等。
  • 发送邮件,短信,OA消息通知等。

在 Activiti 中,可以通过以下方式配置任务监听器:

<userTask id="testListener" name="办理节点" activiti:assignee="zhangsan" activiti:candidateUsers="lisi">
      <extensionElements>
        <activiti:taskListener event="create" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>
        <activiti:taskListener event="assignment" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>
        <activiti:taskListener event="complete" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>
        <activiti:taskListener event="delete" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>
      </extensionElements>
    </userTask>

实现自定义任务监听的代码如下:

package com.test.activiti.activiti.listener;

import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.delegate.DelegateTask;
import org.springframework.stereotype.Service;

/**
 * 测试任务监听器
 * @Author dzf62
 * @Description TODO
 * @Date 2023/8/11 18:30
 * @Version 1.0
 */
@Slf4j
@Service
public class TaskListener implements org.activiti.engine.delegate.TaskListener {



    @Override
    public void notify(DelegateTask delegateTask) {
        String eventName = delegateTask.getEventName();
        switch (eventName){
            case EVENTNAME_CREATE:
                create(delegateTask);
                break;
            case EVENTNAME_ASSIGNMENT:
                assigment(delegateTask);
                break;
            case EVENTNAME_COMPLETE:
                complete(delegateTask);
                break;
            case EVENTNAME_DELETE:
                delete(delegateTask);
                break;
            default:
                break;
        }
    }


    public void create(DelegateTask delegateTask){
        System.out.println("============TaskListener start============");
        String taskDefinitionKey = delegateTask.getTaskDefinitionKey();
        String eventName = delegateTask.getEventName();
        System.out.println("事件名称:" + eventName);
        System.out.println("taskDefinitionKey:" + taskDefinitionKey);
        System.out.println("============TaskListener end============");

    }

    public void assigment(DelegateTask delegateTask){
        System.out.println("============TaskListener start============");
        String taskDefinitionKey = delegateTask.getTaskDefinitionKey();
        String eventName = delegateTask.getEventName();
        System.out.println("事件名称:" + eventName);
        System.out.println("taskDefinitionKey:" + taskDefinitionKey);
        System.out.println("============TaskListener end============");
    }

    public void complete(DelegateTask delegateTask){
        System.out.println("============TaskListener start============");
        String taskDefinitionKey = delegateTask.getTaskDefinitionKey();
        String eventName = delegateTask.getEventName();
        System.out.println("事件名称:" + eventName);
        System.out.println("taskDefinitionKey:" + taskDefinitionKey);
        System.out.println("============TaskListener end============");
    }


    public void delete(DelegateTask delegateTask){
        System.out.println("============TaskListener start============");
        String taskDefinitionKey = delegateTask.getTaskDefinitionKey();
        String eventName = delegateTask.getEventName();
        System.out.println("事件名称:" + eventName);
        System.out.println("taskDefinitionKey:" + taskDefinitionKey);
        System.out.println("============TaskListener end============");
    }
}

执行监听器

执行监听器是一种允许你在流程实例的不同生命周期事件上执行操作的机制。与任务监听器类似,执行监听器在流程实例创建、开始、结束等事件发生时可以被触发。

activiti的源码中,执行监听器事件包括:

image.png

  • start:在流程实例启动时触发。
  • end:在流程实例结束时触发。
  • take:流程连线被执行时触发。

可以通过配置执行监听器来执行以下类型的操作:

  • 在流程实例启动时初始化数据或执行特定操作。
  • 在流程实例结束时进行清理操作或生成报告。

在 Activiti 中,可以通过以下方式配置执行监听器:

<userTask id="testListener" name="办理节点" activiti:assignee="zhangsan" activiti:candidateUsers="lisi">
      <extensionElements>
        <activiti:executionListener event="start" class="com.test.activiti.activiti.listener.ExecuteListener"></activiti:executionListener>
        <activiti:executionListener event="end" class="com.test.activiti.activiti.listener.ExecuteListener"></activiti:executionListener>
        <activiti:executionListener event="take" class="com.test.activiti.activiti.listener.ExecuteListener"></activiti:executionListener>
      </extensionElements>
    </userTask>

实现自定义执行监听器代码如下:

package com.test.activiti.activiti.listener;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;

/**
 * @Author dzf62
 * @Description TODO
 * @Date 2023/8/12 21:17
 * @Version 1.0
 */
public class ExecuteListener implements ExecutionListener {
    @Override
    public void notify(DelegateExecution execution) throws Exception {
        String eventName = execution.getEventName();
        switch (eventName){
            case EVENTNAME_START:
                start(execution);
                break;
            case EVENTNAME_END:
                end(execution);
                break;
            case EVENTNAME_TAKE:
                take(execution);
                break;
            default:
                break;
        }
    }


    public void start(DelegateExecution execution){
        System.out.println("============executionListener start============");
        String eventName = execution.getEventName();
        String currentActivitiId = execution.getCurrentActivityId();
        System.out.println("事件名称:" + eventName);
        System.out.println("ActivitiId:" + currentActivitiId);
        System.out.println("============executionListener  end============");
    }

    public void end(DelegateExecution execution){
        System.out.println("============executionListener start============");
        String eventName = execution.getEventName();
        String currentActivitiId = execution.getCurrentActivityId();
        System.out.println("事件名称:" + eventName);
        System.out.println("ActivitiId:" + currentActivitiId);
        System.out.println("============executionListener  end============");
    }

    public void take(DelegateExecution execution){
        System.out.println("============executionListener start============");
        String eventName = execution.getEventName();
        String currentActivitiId = execution.getCurrentActivityId();
        System.out.println("事件名称:" + eventName);
        System.out.println("ActivitiId:" + currentActivitiId);
        System.out.println("============executionListener  end============");
    }
}

验证任务监听器与执行监听器的事件监听顺序

首先设计一个最简单的流程图,设计如下,使用原生的activiti的modeler,重点是添加任务监听器和执行监听器:

Image.png 对应bpmn如下:

<?xml version="1.0" encoding="UTF-8"?>

<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">

  <process id="测试监听器流程" isExecutable="true">

    <startEvent id="start" name="开始"></startEvent>

    <userTask id="testListener" name="办理节点" activiti:assignee="zhangsan" activiti:candidateUsers="lisi">

      <extensionElements>

        <activiti:formProperty id="name" name="姓名" type="string" variable="张三"></activiti:formProperty>

        <activiti:executionListener event="start" class="com.test.activiti.activiti.listener.ExecuteListener"></activiti:executionListener>

        <activiti:executionListener event="end" class="com.test.activiti.activiti.listener.ExecuteListener"></activiti:executionListener>

        <activiti:executionListener event="take" class="com.test.activiti.activiti.listener.ExecuteListener"></activiti:executionListener>

        <activiti:taskListener event="create" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>

        <activiti:taskListener event="assignment" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>

        <activiti:taskListener event="complete" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>

        <activiti:taskListener event="delete" class="com.test.activiti.activiti.listener.TaskListener"></activiti:taskListener>

      </extensionElements>

    </userTask>

    <sequenceFlow id="sid-6BA47516-0661-4858-AC94-F075196FC8E8" sourceRef="start" targetRef="testListener"></sequenceFlow>

    <endEvent id="sid-2BCD59DB-320E-43FC-9BB4-0ACA61CCE7F0"></endEvent>

    <sequenceFlow id="sid-A38F12AC-7AA8-4BEF-9AC5-A5442C2A979D" sourceRef="testListener" targetRef="sid-2BCD59DB-320E-43FC-9BB4-0ACA61CCE7F0"></sequenceFlow>

  </process>

  <bpmndi:BPMNDiagram id="BPMNDiagram_测试监听器流程">

    <bpmndi:BPMNPlane bpmnElement="测试监听器流程" id="BPMNPlane_测试监听器流程">

      <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">

        <omgdc:Bounds height="30.0" width="30.0" x="74.99999841054293" y="314.9999933242803"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="testListener" id="BPMNShape_testListener">

        <omgdc:Bounds height="80.0" width="100.0" x="195.00000447697187" y="270.00000619888414"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="sid-2BCD59DB-320E-43FC-9BB4-0ACA61CCE7F0" id="BPMNShape_sid-2BCD59DB-320E-43FC-9BB4-0ACA61CCE7F0">

        <omgdc:Bounds height="28.0" width="28.0" x="470.1110768748659" y="315.9999909698969"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNEdge bpmnElement="sid-6BA47516-0661-4858-AC94-F075196FC8E8" id="BPMNEdge_sid-6BA47516-0661-4858-AC94-F075196FC8E8">

        <omgdi:waypoint x="104.8766665764206" y="328.0804245491744"></omgdi:waypoint>

        <omgdi:waypoint x="195.00000447697187" y="316.45161469650725"></omgdi:waypoint>

      </bpmndi:BPMNEdge>

      <bpmndi:BPMNEdge bpmnElement="sid-A38F12AC-7AA8-4BEF-9AC5-A5442C2A979D" id="BPMNEdge_sid-A38F12AC-7AA8-4BEF-9AC5-A5442C2A979D">

        <omgdi:waypoint x="295.00000447697187" y="314.1821598253234"></omgdi:waypoint>

        <omgdi:waypoint x="470.15979454088495" y="328.8330628497661"></omgdi:waypoint>

      </bpmndi:BPMNEdge>

    </bpmndi:BPMNPlane>

  </bpmndi:BPMNDiagram>

</definitions>

在测试任务监听器与执行监听器的执行顺序时,我们对该用户任务节点的任务监听器和执行监听器都添加了所有的监听事件,接下来只需要在启动流程和办理第一个节点的任务,查看打印的内容就可以看出任务监听器和执行监听器各个事件监听的触发时机

首先,启动流程时的打印日志如下:

============executionListener start============

事件名称:start

ActivitiId:testListener

============executionListener  end============

============TaskListener start============

事件名称:assignment

taskDefinitionKey:testListener

============TaskListener end============

============TaskListener start============

事件名称:create

taskDefinitionKey:testListener

============TaskListener end============

说明流程在到达用户任务节点时,任务监听器的事件监听顺序如下:assignment->create;而执行监听器只会触发start事件

然后,办理该用户任务时,打印日志如下:

============TaskListener start============

事件名称:complete

taskDefinitionKey:testListener

============TaskListener end============

============TaskListener start============

事件名称:delete

taskDefinitionKey:testListener

============TaskListener end============

============executionListener start============

事件名称:end

ActivitiId:testListener

============executionListener  end============

任务监听器的事件监听顺序如下:complete->delete;执行监听器只触发了end事件