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

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

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

任务监听器

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

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

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

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

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

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

xml 复制代码
<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>

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

java 复制代码
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的源码中,执行监听器事件包括:

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

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

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

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

xml 复制代码
<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>

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

java 复制代码
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,重点是添加任务监听器和执行监听器:

对应bpmn如下:

xml 复制代码
<?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>

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

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

js 复制代码
============executionListener start============

事件名称:start

ActivitiId:testListener

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

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

事件名称:assignment

taskDefinitionKey:testListener

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

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

事件名称:create

taskDefinitionKey:testListener

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

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

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

js 复制代码
============TaskListener start============

事件名称:complete

taskDefinitionKey:testListener

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

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

事件名称:delete

taskDefinitionKey:testListener

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

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

事件名称:end

ActivitiId:testListener

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

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

相关推荐
F-2H13 分钟前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
苹果酱056715 分钟前
「Mysql优化大师一」mysql服务性能剖析工具
java·vue.js·spring boot·mysql·课程设计
_oP_i1 小时前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx1 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
武子康2 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘3 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意3 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
刘大辉在路上3 小时前
突发!!!GitLab停止为中国大陆、港澳地区提供服务,60天内需迁移账号否则将被删除
git·后端·gitlab·版本管理·源代码管理
FF在路上4 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进4 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html