本文介紹執行監聽器與任務監聽器的基本原理和使用方法。當流程途徑連線或者節點的時候,會觸發對應的事件類型。執行監聽器與任務監聽器在生產中經常會用在幾個方面:
- 動態分配節點處理人。通過前一個節點設置的變量,在運行到下一個節點時設置對應的處理人;
- 當流程運行到某個節點時,發送郵件或短信給待辦用戶;
- 統計流程處理時長,是否超時等;
- 業務層面數據處理。
任務監聽器顧名思義是監聽任務的。任務監聽器的生命周期如下圖所示,會經歷assignment、create、complete、delete。當流程引擎觸發這四種事件類型時,對應的任務監聽器會捕獲其事件類型,再按照監聽器的處理邏輯進行處理。
執行監聽器則監聽流程的所有節點和連線。主要有start、end、take事件。其中節點有start、end兩種事件,而連線則有take事件。下圖是執行監聽器的生命周期:
接下來通過代碼去演示監聽器效果。 首先我們創建一個執行監聽器的類:
package listener; import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.ExecutionListener; public class MyExecutionListener implements ExecutionListener { public void notify(DelegateExecution execution) throws Exception { 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============"); } }
自定義執行監聽器需要實現ExecutionListener接口,並且實現notify方法。這里我們打印對應的事件和活動節點id
接下來創建一個自定任務監聽器:
package listener; import org.activiti.engine.delegate.DelegateTask; import org.activiti.engine.delegate.TaskListener; public class MyTaskListener implements TaskListener{ public void notify(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============"); } }
自定義任務監聽器需要實現TaskListener接口,並且實現notify方法。這里我們打印對應的事件和任務節點鍵值(即bpmn圖里userTask的id)。
之后新建一個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/test"> <process id="listenerBpmProcess" name="My process" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="myTask1" activiti:assignee="張三"> <extensionElements> <activiti:executionListener event="start" class="listener.MyExecutionListener"></activiti:executionListener> <activiti:executionListener event="end" class="listener.MyExecutionListener"></activiti:executionListener> <activiti:taskListener event="all" class="listener.MyTaskListener"></activiti:taskListener> </extensionElements> </userTask> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_listenerBpmProcess"> <bpmndi:BPMNPlane bpmnElement="listenerBpmProcess" id="BPMNPlane_listenerBpmProcess"> <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"> <omgdc:Bounds height="41.0" width="35.0" x="505.0" y="40.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"> <omgdc:Bounds height="55.0" width="105.0" x="470.0" y="150.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"> <omgdc:Bounds height="35.0" width="35.0" x="505.0" y="240.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1"> <omgdi:waypoint x="522.0" y="81.0"></omgdi:waypoint> <omgdi:waypoint x="522.0" y="150.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"> <omgdi:waypoint x="522.0" y="205.0"></omgdi:waypoint> <omgdi:waypoint x="522.0" y="240.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
這里我們給userTask1添加了執行監聽器和任務監聽器。部署bpmn圖后,我們觀察流程運轉時監聽器的觸發時機和作用,啟動流程:
public void startProcessById() { RuntimeService runtimeService = pe.getRuntimeService(); ProcessInstance pi = runtimeService.startProcessInstanceById("listenerBpmProcess:1:4"); }
流程啟動后,從開始節點運轉到userTask1節點,觀察控制台輸出:
============executionListener start============
事件名稱:start
ActivitiId:usertask1
============executionListener end============
============TaskListener start============
事件名稱:assignment
taskDefinitionKey:usertask1
============TaskListener end============
============TaskListener start============
事件名稱:create
taskDefinitionKey:usertask1
============TaskListener end============
可以看到流程走到userTask1節點時,首先觸發start事件,調用我們自定義的執行監聽器,隨后觸發assignment和create事件,執行自定義任務監聽器的內容。注意這里是先觸發assignment進行人員分配,再觸發create事件,與一般的認知有些差異。
接下來通過taskService的complete方法完成userTask1節點上流程的提交,觀察控制台輸出:
============TaskListener start============
事件名稱:complete
taskDefinitionKey:usertask1
============TaskListener end============
============TaskListener start============
事件名稱:delete
taskDefinitionKey:usertask1
============TaskListener end============
============executionListener start============
事件名稱:end
ActivitiId:usertask1
============executionListener end============
可以看到userTask1節點提交的時候,首先觸發complete事件再觸發delete事件,最后觸發end事件。
以上就是執行監聽器與任務監聽器的基本使用方式。實際工程中,由於流程節點十分多,並且流程和業務常常需要進行微調,通常是不會在bpmn圖上逐個節點添加監聽器的,往往是在解析bpmn對象期間利用對象解析器動態添加監聽器。這里涉及的原理比較復雜,留到后面的文章再討論。
到本文為止,講的都是activiti的入門用法,可以順利跑通一個流程,還能在流程運行的途中進行一些監聽和操作。activiti的入門概念不少,但使用並不復雜。
原文鏈接:https://blog.csdn.net/sadoshi/article/details/104698749/