Activiti6.0 (ocho) uso de oyentes

Tabla de contenido

I. Introducción

En segundo lugar, el uso del monitor.

Tres, categoría de oyente

1. Escucha de ejecución (ExecutionListener)

2. Escucha de tareas (TaskListener)

3. Escucha de eventos (ActivitiEventListener)

4. Prioridad de ejecución del oyente


I. Introducción

En el artículo anterior, el oyente se usó realmente cuando se hablaba de la distribución de manejadores. El punto más flexible de Activiti es que proporciona una variedad de oyentes y los eventos de monitoreo correspondientes, que pueden satisfacer la mayoría de las necesidades comerciales, así que aprenda a usar el El oyente también es un paso muy importante para dominar Activiti.

 

En segundo lugar, el uso del monitor.

Cuando se usa Activiti, se suele utilizar como motor subyacente, y el motor suele estar separado del negocio, por lo que el motor es necesario para promover el negocio, es decir, cuando el proceso se ejecuta hasta una determinada etapa, ejecutaremos el lógica de negocio correspondiente, que depende del oyente de Activiti. Los escenarios comunes son:

1. Asignación dinámica de personal de enlace

2. Es necesario registrar la información del enlace al principio o al final de un enlace, o insertar algunos datos registrados.

3. Es necesario realizar algunos negocios personalizados al principio o al final de la tarea.

...

En resumen, el oyente está acostumbrado a satisfacer una variedad de necesidades comerciales complejas.

 

Tres, categoría de oyente

Según el tipo de seguimiento, existen aproximadamente tres tipos:

  • Oyente de ejecución
  • Oyente de tareas
  • Oyente de eventos

Introduzca uno por uno a continuación

1. Escucha de ejecución ( ExecutionListener )

El oyente se puede configurar en nodos y líneas. Hay tres tipos principales de eventos:

  • inicio: Activado al principio
  • end: Activado al final
  • tomar: se utiliza principalmente para monitorear la línea de proceso, se activa cuando el proceso fluye hacia la línea

Como desea utilizar un oyente, primero debe personalizar uno usted mismo y debe implementar org.activiti.engine.delegate.ExecutionListener, de la siguiente manera:

package activiti.activiti.listener;

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

/**
 * Created by xujia on 2020/2/6
 */
public class ExecutionListenerImpl implements ExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) {
        String event = delegateExecution.getEventName();
        switch (event) {
            case "start" :
                System.out.println("start event");
                break;
            case "end" :
                System.out.println("end event");
                break;
            case "take" :
                System.out.println("take event");
                break;
        }
    }
}

Luego es para configurar en el diagrama de flujo, primero mire el diagrama de flujo simple que dibujé:

Configuré dos oyentes en el primer enlace, a saber, eventos de inicio y finalización, y configuré eventos de toma en 3 lugares en línea. El método de configuración es el siguiente:

Por supuesto, la configuración del oyente anterior también puede usar expresiones delegadas, usando la inyección de resorte para inicializar un oyente personalizado, la configuración es la siguiente:

La configuración de la línea 3 es la misma, el xml es el siguiente:

<?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="listenerTest" name="监听器测试" isExecutable="true">
    <startEvent id="startEvent1"></startEvent>
    <endEvent id="sid-39CC4B7B-E9FF-4C68-B2D2-4ADC6DD80560"></endEvent>
    <userTask id="sid-E27274BD-5FFE-4484-B0B7-EFAC35F180CA" name="第一环节" activiti:candidateUsers="test">
      <extensionElements>
        <activiti:executionListener event="start" class="activiti.activiti.listener.ExecutionListenerImpl"></activiti:executionListener>
        <activiti:executionListener event="end" class="activiti.activiti.listener.ExecutionListenerImpl"></activiti:executionListener>
        <modeler:user-info-firstname-test xmlns:modeler="http://activiti.com/modeler"><![CDATA[test]]></modeler:user-info-firstname-test>
        <modeler:activiti-idm-candidate-user xmlns:modeler="http://activiti.com/modeler"><![CDATA[true]]></modeler:activiti-idm-candidate-user>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="sid-E1583F4D-6998-48A6-B4EF-C0623ECD86A7" name="第二环节" activiti:candidateUsers="test">
      <extensionElements>
        <modeler:user-info-firstname-test xmlns:modeler="http://activiti.com/modeler"><![CDATA[test]]></modeler:user-info-firstname-test>
        <modeler:activiti-idm-candidate-user xmlns:modeler="http://activiti.com/modeler"><![CDATA[true]]></modeler:activiti-idm-candidate-user>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-CEE5F74F-8FDA-44CA-BB47-5E9B0531F08B" name="线1" sourceRef="startEvent1" targetRef="sid-E27274BD-5FFE-4484-B0B7-EFAC35F180CA"></sequenceFlow>
    <sequenceFlow id="sid-CA16842F-0D76-4CD0-B38F-17030B7181BD" name="线2" sourceRef="sid-E27274BD-5FFE-4484-B0B7-EFAC35F180CA" targetRef="sid-E1583F4D-6998-48A6-B4EF-C0623ECD86A7"></sequenceFlow>
    <sequenceFlow id="sid-D0B1DEB4-58AB-4FB2-80D9-1EFC48C37D28" name="线3" sourceRef="sid-E1583F4D-6998-48A6-B4EF-C0623ECD86A7" targetRef="sid-39CC4B7B-E9FF-4C68-B2D2-4ADC6DD80560">
      <extensionElements>
        <activiti:executionListener event="take" class="activiti.activiti.listener.ExecutionListenerImpl"></activiti:executionListener>
      </extensionElements>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_listenerTest">
    <bpmndi:BPMNPlane bpmnElement="listenerTest" id="BPMNPlane_listenerTest">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-39CC4B7B-E9FF-4C68-B2D2-4ADC6DD80560" id="BPMNShape_sid-39CC4B7B-E9FF-4C68-B2D2-4ADC6DD80560">
        <omgdc:Bounds height="28.0" width="28.0" x="701.0" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-E27274BD-5FFE-4484-B0B7-EFAC35F180CA" id="BPMNShape_sid-E27274BD-5FFE-4484-B0B7-EFAC35F180CA">
        <omgdc:Bounds height="80.0" width="100.0" x="223.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-E1583F4D-6998-48A6-B4EF-C0623ECD86A7" id="BPMNShape_sid-E1583F4D-6998-48A6-B4EF-C0623ECD86A7">
        <omgdc:Bounds height="80.0" width="100.0" x="450.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-CA16842F-0D76-4CD0-B38F-17030B7181BD" id="BPMNEdge_sid-CA16842F-0D76-4CD0-B38F-17030B7181BD">
        <omgdi:waypoint x="323.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-CEE5F74F-8FDA-44CA-BB47-5E9B0531F08B" id="BPMNEdge_sid-CEE5F74F-8FDA-44CA-BB47-5E9B0531F08B">
        <omgdi:waypoint x="130.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="223.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-D0B1DEB4-58AB-4FB2-80D9-1EFC48C37D28" id="BPMNEdge_sid-D0B1DEB4-58AB-4FB2-80D9-1EFC48C37D28">
        <omgdi:waypoint x="550.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="701.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Luego inicia el proceso:

/**
     * 监听器测试
     */
    @Test
    public void listenerTest() {
        // 1、发布流程,当流程的key相同时则以版本来控制,每次启动流程实例时默认取最新版本
        Deployment deployment = repositoryService.createDeployment().name("监听器测试流程").addClasspathResource("processes/listener.bpmn20.xml").deploy();

        // 2、启动一个流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("listenerTest");

    }

El evento de inicio se puede activar al iniciar, el evento de finalización se activa cuando se completa la primera tarea de enlace y el evento de toma se activa en este momento debido a la necesidad de pasar por la línea 3 cuando se completa la segunda tarea de enlace.

Resumen: Los eventos de inicio y finalización también son aplicables a los nodos de inicio y finalización. Puede utilizar este oyente para implementar algún monitoreo global, como el inicio y final del proceso, y el monitoreo de ciertas líneas de proceso.

2. Escucha de tareas (TaskListener)

El oyente solo puede escuchar nodos con información de tareas. Los nodos de inicio y finalización no se pueden monitorear porque no hay tareas en Activiti. Soporta cuatro tipos de eventos de monitoreo:

  • crear: se activa cuando se crea la tarea, en este momento se han establecido todas las propiedades
  • asignación: se activa después de que la tarea se delega a alguien, como cuando el controlador se establece a través de una variable, que se activa antes del evento de creación
  • complete: se activa después de que se completa la tarea y antes de que se elimine de los datos de tiempo de ejecución.
  • eliminar: ocurre antes de que la tarea esté a punto de eliminarse.

El uso es similar al del escucha de ejecución. Primero, personalice una clase de implementación, de la siguiente manera:

package activiti.activiti.listener;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

/**
 * Created by xujia on 2020/2/6
 */
public class AssigneeListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        String event = delegateTask.getEventName();
        switch (event) {
            case "create" :
                System.out.println("create event");
                break;
            case "assignment" :
                System.out.println("assignment event");
                break;
            case "complete" :
                System.out.println("complete event");
                break;
            case "delete" :
                System.out.println("delete event");
                break;
        }
    }
}

Luego configuré cuatro oyentes en el primer enlace.

Al mismo tiempo, también configuré dos escuchas de ejecución en el primer enlace, y luego configuré el controlador "Li Si" para el primer enlace usando variables de proceso para iniciar el proceso:

@Test
    public void listenerTest() {
        // 1、发布流程,当流程的key相同时则以版本来控制,每次启动流程实例时默认取最新版本
        Deployment deployment = repositoryService.createDeployment().name("监听器测试流程").addClasspathResource("processes/listener.bpmn20.xml").deploy();

        Map<String, Object> variables = new HashMap<>();
        variables.put("userId", "李四");
        // 2、启动一个流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("listenerTest", variables);

    }

Vea que la siguiente información esté impresa en la consola a su vez:

start event
assignment event
create event

Explique que el evento de inicio del oyente de ejecución se ejecuta antes que el oyente de la tarea. Debido a que la variable de proceso se usa para asignar el controlador para desencadenar el evento de asignación, en este momento la tabla act_ru_task también agregará una primera tarea de enlace, por lo que el evento de creación se activa y el evento de asignación es lo primero. Ejecuta con create y luego completa la primera tarea:

@Test
    public void completeTask() {
        String taskId = "87502";
        taskService.complete(taskId);
    }

La consola imprime secuencialmente:

complete event
delete event
end event

Explique que el evento final del oyente de ejecución lo ejecuta el oyente de la tarea. Debido a que la tarea del primer enlace se completa, se activa el evento completo. Una vez completada la tarea, se eliminará de la tabla act_ru_task, lo que activará el eliminar evento.

3. Escucha de eventos (ActivitiEventListener)

Después de comprender los dos oyentes anteriores, podemos encontrar que el oyente de ejecución y el oyente de tareas deben configurarse durante el diseño del proceso, y solo para un determinado proceso, en caso de que todos los procesos deban configurarse y su negocio sea común. tipo de oyente que puede escuchar globalmente? Por supuesto, Activiti lo proporciona, y este es el oyente de eventos. Le permite recibir un recordatorio cuando el motor activa un tipo de evento específico y también le permite agregar oyentes dinámicamente durante el tiempo de ejecución.

Los eventos admitidos son los siguientes: (La lista se selecciona del manual Activiti5.16, se agregan 6 nuevos tipos, pero los de uso común ya se incluyen a continuación, y puede verificarlo si está interesado ActivitiEvent枚举类)

Nombre del evento descripción Tipo de evento
ENGINE_CREATED El motor de proceso supervisado por el oyente se ha creado y está listo para aceptar llamadas a la API. org.activiti...ActivitiEvent
MOTOR_CERRADO El motor de proceso supervisado por el oyente se ha cerrado y ya no acepta llamadas a la API. org.activiti...ActivitiEvent
ENTITY_CREATED Se crea una nueva entidad. La entidad está incluida en el evento. org.activiti...ActivitiEntityEvent
ENTITY_INITIALIZED Se crea una nueva entidad y se completa la inicialización. Si la creación de esta entidad incluye la creación de subentidades, este evento se activará después de que se complete la creación / inicialización de todas las subentidades. Esta es ENTITY_CREATEDla diferencia con eso. org.activiti...ActivitiEntityEvent
ENTITY_UPDATED Se actualizó una entidad existente. La entidad está incluida en el evento. org.activiti...ActivitiEntityEvent
ENTITY_DELETED La entidad existente ha sido eliminada. La entidad está incluida en el evento. org.activiti...ActivitiEntityEvent
ENTITY_SUSPENDED Entidades existentes suspendidas. La entidad está incluida en el evento. Será lanzado por ProcessDefinitions, ProcessInstances y Tasks. org.activiti...ActivitiEntityEvent
ENTITY_ACTIVATED Se activa una entidad existente y la entidad se incluye en el evento. Será lanzado por ProcessDefinitions, ProcessInstances y Tasks. org.activiti...ActivitiEntityEvent
JOB_EXECUTION_SUCCESS El trabajo se ejecuta con éxito. El trabajo está incluido en el evento. org.activiti...ActivitiEntityEvent
JOB_EXECUTION_FAILURE La ejecución del trabajo falló. La información del trabajo y la excepción se incluye en el evento. org.activiti...ActivitiEntityEvent y org.activiti...ActivitiExceptionEvent
JOB_RETRIES_DECREMENTED Debido a que la ejecución del trabajo falló, el número de reintentos disminuyó. El trabajo está incluido en el evento. org.activiti...ActivitiEntityEvent
TIMER_FIRED 触发了定时器。job包含在事件中。 org.activiti...ActivitiEntityEvent
JOB_CANCELED 取消了一个作业。事件包含取消的作业。作业可以通过API调用取消, 任务完成后对应的边界定时器也会取消,在新流程定义发布时也会取消。 org.activiti...ActivitiEntityEvent
ACTIVITY_STARTED 一个节点开始执行 org.activiti...ActivitiActivityEvent
ACTIVITY_COMPLETED 一个节点成功结束 org.activiti...ActivitiActivityEvent
ACTIVITY_SIGNALED 一个节点收到了一个信号 org.activiti...ActivitiSignalEvent
ACTIVITY_MESSAGE_RECEIVED 一个节点收到了一个消息。在节点收到消息之前触发。收到后,会触发ACTIVITY_SIGNALACTIVITY_STARTED,这会根据节点的类型(边界事件,事件子流程开始事件) org.activiti...ActivitiMessageEvent
ACTIVITY_ERROR_RECEIVED 一个节点收到了一个错误事件。在节点实际处理错误之前触发。 事件的activityId对应着处理错误的节点。 这个事件后续会是ACTIVITY_SIGNALLEDACTIVITY_COMPLETE, 如果错误发送成功的话。 org.activiti...ActivitiErrorEvent
UNCAUGHT_BPMN_ERROR 抛出了未捕获的BPMN错误。流程没有提供针对这个错误的处理器。 事件的activityId为空。 org.activiti...ActivitiErrorEvent
ACTIVITY_COMPENSATE 一个节点将要被补偿。事件包含了将要执行补偿的节点id。 org.activiti...ActivitiActivityEvent
VARIABLE_CREATED 创建了一个变量。事件包含变量名,变量值和对应的分支或任务(如果存在)。 org.activiti...ActivitiVariableEvent
VARIABLE_UPDATED 更新了一个变量。事件包含变量名,变量值和对应的分支或任务(如果存在)。 org.activiti...ActivitiVariableEvent
VARIABLE_DELETED 删除了一个变量。事件包含变量名,变量值和对应的分支或任务(如果存在)。 org.activiti...ActivitiVariableEvent
TASK_ASSIGNED 任务被分配给了一个人员。事件包含任务。 org.activiti...ActivitiEntityEvent
TASK_CREATED 创建了新任务。它位于ENTITY_CREATE事件之后。当任务是由流程创建时, 这个事件会在TaskListener执行之前被执行。 org.activiti...ActivitiEntityEvent
TASK_COMPLETED 任务被完成了。它会在ENTITY_DELETE事件之前触发。当任务是流程一部分时,事件会在流程继续运行之前, 后续事件将是ACTIVITY_COMPLETE,对应着完成任务的节点。 org.activiti...ActivitiEntityEvent
TASK_TIMEOUT 任务已超时,在TIMER_FIRED事件之后,会触发用户任务的超时事件, 当这个任务分配了一个定时器的时候。 org.activiti...ActivitiEntityEvent
PROCESS_COMPLETED 流程已结束。在最后一个节点的ACTIVITY_COMPLETED事件之后触发。 当流程到达的状态,没有任何后续连线时, 流程就会结束。 org.activiti...ActivitiEntityEvent
MEMBERSHIP_CREATED 用户被添加到一个组里。事件包含了用户和组的id。 org.activiti...ActivitiMembershipEvent
MEMBERSHIP_DELETED 用户被从一个组中删除。事件包含了用户和组的id。 org.activiti...ActivitiMembershipEvent
MEMBERSHIPS_DELETED 所有成员被从一个组中删除。在成员删除之前触发这个事件,所以他们都是可以访问的。 因为性能方面的考虑,不会为每个成员触发单独的MEMBERSHIP_DELETED事件。 org.activiti...ActivitiMembe

上面一大堆事件可能看的很头疼,常用的无非是ACTIVITY_STARTED、ACTIVITY_COMPLETED、TASK_ASSIGNED、TASK_CREATED、TASK_COMPLETED,一切以满足业务为基准~

配置全局监听器,这里以SpringBoot配置为例,老规矩首先自定义实现类:

@Component
public class ActivitiEventListenerImpl implements ActivitiEventListener {

    @Override
    public void onEvent(ActivitiEvent event) {
        // 这里可以根据需要自行强转event的实现类,如获取流转实例对象可强转为ActivitiEntityEventImpl,如获取环节信息可强转为ActivitiActivityEventImpl,等等等
        switch (event.getType()) {
            case TASK_CREATED:
                System.out.println("TASK_CREATED event");
                break;
            case TASK_COMPLETED:
                System.out.println("TASK_COMPLETED event");
                break;
            case ACTIVITY_COMPLETED:
                System.out.println("ACTIVITY_COMPLETED event");
                break;
            case ACTIVITY_STARTED:
                System.out.println("ACTIVITY_STARTED event");
                break;
        }
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }
}

然后进行Activiti的初始化配置,这里使用Api方式配置:

@Component
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {

    @Autowired
    private ActivitiEventListenerImpl activitiEventListener;

    @Override
    public void configure(SpringProcessEngineConfiguration configuration) {
        Map<String, List<ActivitiEventListener>> activitiEventListenerMap = new HashMap<>();
        // 设置全局监听器
        activitiEventListenerMap.put(ActivitiEventType.ACTIVITY_STARTED.name(), Lists.newArrayList(activitiEventListener));
        activitiEventListenerMap.put(ActivitiEventType.ACTIVITY_COMPLETED.name(), Lists.newArrayList(activitiEventListener));
        activitiEventListenerMap.put(ActivitiEventType.TASK_CREATED.name(), Lists.newArrayList(activitiEventListener));
        activitiEventListenerMap.put(ActivitiEventType.TASK_COMPLETED.name(), Lists.newArrayList(activitiEventListener));
        configuration.setTypedEventListeners(activitiEventListenerMap);
    }
}

可以看到我分别注册了四个事件的监听,所有节点的开始与完成,以及所有任务的开始与完成,在自定义的监听器内均会收到提,最后启动上面的流程,看到控制台输出:

ACTIVITY_STARTED event
ACTIVITY_COMPLETED event
start event
ACTIVITY_STARTED event
assignment event
create event
TASK_CREATED event

来分析下输出信息,首先流程实例启动触发开始环节的事件监听器-节点开始与节点完成事件,流转到第一环节后,按顺序依次触发执行监听器的开始事件,事件监听器的节点开始事件,任务监听器的处理人分配与任务创建事件,事件监听器的任务创建事件。

从输出来看,执行监听器先与事件监听器,任务监听器先于事件监听器,然后完成该任务:

complete event
TASK_COMPLETED event
delete event
end event
ACTIVITY_COMPLETED event
ACTIVITY_STARTED event
TASK_CREATED event

由于完成了第一环节的任务,因此首先触发的是任务监听器的完成事件,然后是事件监听器的任务完成,接着是任务监听的删除事件,最后是执行监听器的节点结束事件以及事件监听器的节点结束事件,此时流转到第二环节,依次触发对应的事件监听。

关于ActivitiEventListener接口的onEvent方法的ActivitiEvent接口:

public interface ActivitiEvent {

  /**
   * @return type of event.
   */
  ActivitiEventType getType();

  /**
   * @return the id of the execution this event is associated with. Returns null, if the event was not dispatched from within an active execution.
   */
  String getExecutionId();

  /**
   * @return the id of the process instance this event is associated with. Returns null, if the event was not dispatched from within an active execution.
   */
  String getProcessInstanceId();

  /**
   * @return the id of the process definition this event is associated with. Returns null, if the event was not dispatched from within an active execution.
   */
  String getProcessDefinitionId();

}

该接口自身只有四个方法,在实际业务场景下通常无法满足,这时候我们就需要在对应的触发事件类型下去获取对应的实现类,实现类与事件类型是相关的,可以看到它有很多实现类以及接口:

在运行阶段添加或删除监听器:

可以通过Api(RuntimeService)实现

/**
   * Adds an event-listener which will be notified of ALL events by the dispatcher.
   * 
   * @param listenerToAdd
   *          the listener to add
   */
  void addEventListener(ActivitiEventListener listenerToAdd);

  /**
   * Adds an event-listener which will only be notified when an event occurs, which type is in the given types.
   * 
   * @param listenerToAdd
   *          the listener to add
   * @param types
   *          types of events the listener should be notified for
   */
  void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types);

  /**
   * Removes the given listener from this dispatcher. The listener will no longer be notified, regardless of the type(s) it was registered for in the first place.
   * 
   * @param listenerToRemove
   *          listener to remove
   */
  void removeEventListener(ActivitiEventListener listenerToRemove);

注意在运行期添加的监听器在引擎重启后就消失了。

4、监听器执行优先级

如果在同一个节点同时配置三种监听器时,事件监听器相对来说优先级总是最低的,而其余两个监听器之间则要分情况来说:如果是开始,则执行监听器优先级高;如果是结束,则任务监听器优先级高。总而言之,粗糙点来说,执行监听器>任务监听器>事件监听器。

Supongo que te gusta

Origin blog.csdn.net/m0_38001814/article/details/104197670
Recomendado
Clasificación