1、啓動事件 java
每一個流程都須要從啓動事件開始,根據不一樣的需求有空啓動、定時啓動、異常啓動和消息啓動。 ide
異常啓動事件不能用於主流程,必須嵌入到事件子流程中。 函數
一、定時啓動事件 工具
定時啓動標籤timerEventDefinition嵌套在啓動事件startEvent中就構成了定時啓動事件。定時啓動事件能夠有三種啓動屬性: 測試
以下定義了一個定時啓動事件,部署流程5分鐘後啓動: this
<startEvent id="timerstartevent1" name="Timer start"> <timerEventDefinition> <timeDuration>PT5M</timeDuration> </timerEventDefinition> </startEvent>
定時啓動的測試代碼以下: spa
@Deployment(resources = "chapter11/timerEvent/timerStartEvent.bpmn") public void testTriggerAutomatic() throws Exception { // 部署以後引擎會自動建立一個定時啓動事件的Job JobQuery jobQuery = managementService.createJobQuery(); assertEquals(1, jobQuery.count()); // 模擬時間5分鐘以後 SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss"); System.out.println(".... start ...." + sdf.format(new Date())); Context.getProcessEngineConfiguration().getClock().setCurrentTime(new Date(System.currentTimeMillis() + ((50 * 60 * 1000) + 5000))); waitForJobExecutorToProcessAllJobs(5000L, 1L); System.out.println(".... end ...." + sdf.format(new Date())); assertEquals(0, jobQuery.count()); // 檢查是否啓動了流程實例 long count = runtimeService.createProcessInstanceQuery().processDefinitionKey("timerStartEvent").count(); assertEquals(1, count); }
Context.getProcessEngineConfiguration().getClock().setCurrentTime(new Date(System.currentTimeMillis() + ((50 * 60 * 1000) + 5000))); waitForJobExecutorToProcessAllJobs(5000L, 1L);這兩行代碼用activiti提供的測試工具用5s模擬5分鐘,我本身運行的時候發現Context.getProcessEngineConfiguration()的結果是null,改用測試類繼承的PluggableActivitiTestCase類的getProcessEngineConfiguration()後正常執行。
猜測是做者搞混了?Context.getProcessEngineConfiguration()是非測試時用的代碼? code
定時啓動事件也能夠手動觸發,即API調用觸發,測試代碼以下: orm
@Deployment(resources = "chapter11/timerEvent/timerStartEvent.bpmn") public void testTriggerManual() throws Exception { // 部署以後引擎會自動建立一個定時啓動事件的Job JobQuery jobQuery = managementService.createJobQuery(); assertEquals(1, jobQuery.count()); // 手動觸發做業的執行 Job job = jobQuery.singleResult(); managementService.executeJob(job.getId()); assertEquals(0, jobQuery.count()); // 檢查是否啓動了流程實例 long count = runtimeService.createProcessInstanceQuery().processDefinitionKey("timerStartEvent").count(); assertEquals(1, count); }
定時啓動的job唄記錄在ACT_RU_JOB表中,如下是該表的一些主要字段: xml
二、消息啓動事件
經過一個消息標誌觸發啓動事件。
消息啓動事件的相關代碼:
<message id="MSG_001" name="啓動XXX流程"></message> <process id="messageStartEvent" name="messageStartEvent" isExecutable="true"> <startEvent id="messagestartevent1" name="Start"> <messageEventDefinition messageRef="MSG_001"></messageEventDefinition> </startEvent> <userTask id="usertask1" name="用戶任務" activiti:assignee="kermit"></userTask> <sequenceFlow id="flow1" sourceRef="messagestartevent1" targetRef="usertask1"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow> </process>
以消息啓動事件的測試代碼:
public void testStartMessageEvent(){ ProcessInstance processInstance = this.runtimeService.startProcessInstanceByMessage("啓動流程"); Assert.assertNotNull(processInstance); }
也可使用startProcessInstanceByKey方法來啓動流程,可是這對於消息啓動事件有一個限制:流程只能包含一個消息啓動事件。測試代碼以下:
public void testStartMessageEventByKey() throws Exception { ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("messageStartEvent"); assertNotNull(processInstance); }
測試消息註冊成功的代碼:
@Test @Deployment(resources = "messageStartEvent.bpmn") public void testMessageSubcription(){ EventSubscriptionQueryImpl query = new EventSubscriptionQueryImpl(this.processEngineConfiguration.getCommandExecutor()); EventSubscriptionEntity entity = query.eventName("啓動流程").singleResult(); Assert.assertNotNull(entity); }
沒寫完,要出門了,晚上回來繼續。BTW,今天北京天氣不錯,這會出門還能曬到太陽,下午安。
回來了,筆記繼續。
2、終止結束事件
終止結束事件和空結束事件的區別在於終止結束事件能夠終止整個流程實例的執行,而空結束事件只結束一條輸出流的執行。
上圖的流程中啓動事件後經過一個並行網關獲得一個主任務流程和一個子任務流程。若是主任務完成後到達終止結束事件則整個流程都將結束(包括進行中的子任務),但若是子任務先於主任務結束,則主任務還未結束,整個流程還處於運行狀態。
終止結束事件的XML定義以下:
<endEvent id="terminateendevent1" name="End"> <terminateEventDefinition></terminateEventDefinition> </endEvent>
private void checkFinished(ProcessInstance processInstance) { // 驗證流程已結束 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(processInstance.getProcessInstanceId()).singleResult(); assertNotNull(historicProcessInstance.getEndTime()); // 查詢歷史任務 List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().list(); for (HistoricTaskInstance hti : list) { System.out.println(hti.getName() + " " + hti.getDeleteReason()); } // 流程結束後校驗監聽器設置的變量 HistoricVariableInstance variableInstance = historyService.createHistoricVariableInstanceQuery().variableName("settedOnEnd").singleResult(); assertEquals(true, variableInstance.getValue()); }
其中HistoricTaskInstance.getDeleteReason()獲得任務的刪除緣由屬性,若是任務正常完成則屬性爲complete,若是異常終止爲delete。
3、邊界事件
一、異常邊界事件
下面的xml定義中在一個java service添加了異常邊界事件
<process id="throwErrorManual" name="throwErrorManual" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <serviceTask id="servicetask1" name="自動執行系統任務" activiti:class="me.kafeitu.activiti.chapter11.listener.ThrowErrorManaualService"></serviceTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow2" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow> <boundaryEvent id="boundaryerror1" name="Error" attachedToRef="servicetask1"> <errorEventDefinition errorRef="AIA_ERROR_99"></errorEventDefinition> </boundaryEvent> <userTask id="usertask1" name="處理異常"></userTask> <sequenceFlow id="flow3" sourceRef="boundaryerror1" targetRef="usertask1"></sequenceFlow> <sequenceFlow id="flow4" sourceRef="usertask1" targetRef="servicetask1"></sequenceFlow> <textAnnotation id="textannotation1"> <text>異常代碼:AIA_ERROR_99</text> </textAnnotation> <association id="association1" sourceRef="textannotation1" targetRef="boundaryerror1"></association> </process>
public class ThrowErrorManaualService implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { if (execution.getVariable("pass") == null) { throw new BpmnError("AIA_ERROR_99"); } } }
二、消息邊界事件
定義消息邊界事件的代碼以下:
<process id="messageBoundaryEvent" name="messageBoundaryEvent" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="審覈文件"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow> <boundaryEvent id="boundarymessage1" name="Message" attachedToRef="usertask1" cancelActivity="true"> <messageEventDefinition messageRef="MSG_HELP"></messageEventDefinition> </boundaryEvent> <userTask id="usertask2" name="協助處理"></userTask> <sequenceFlow id="flow3" sourceRef="boundarymessage1" targetRef="usertask2"></sequenceFlow> <sequenceFlow id="flow4" sourceRef="usertask2" targetRef="usertask1"></sequenceFlow> </process>
ExecutionQuery executionQuery = runtimeService.createExecutionQuery().messageEventSubscriptionName("MSG_協助處理"); Execution execution = executionQuery.singleResult(); runtimeService.messageEventReceived("MSG_協助處理", execution.getId());
三、信號邊界事件與消息邊界事件的機制類似
<signal id="S_HELP" name="S_協助處理"></signal> <process id="signalBoundaryEvent" name="Signal Boundary Event" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="審覈文件"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <boundaryEvent id="boundarysignal1" name="Signal" attachedToRef="usertask1" cancelActivity="true"> <signalEventDefinition signalRef="S_HELP"></signalEventDefinition> </boundaryEvent> <userTask id="usertask2" name="協助處理"></userTask> <sequenceFlow id="flow2" sourceRef="boundarysignal1" targetRef="usertask2"></sequenceFlow> <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask1"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow4" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow> </process>
分爲捕獲型和拋出型兩種,定義以下:
<process id="throwAlert" name="My process" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <intermediateThrowEvent id="signalintermediatethrowevent1" name="SignalThrowEvent"> <signalEventDefinition signalRef="alert"></signalEventDefinition> </intermediateThrowEvent> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="signalintermediatethrowevent1"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow2" sourceRef="signalintermediatethrowevent1" targetRef="endevent1"></sequenceFlow> <textAnnotation id="textannotation1"> <text>拋出alert信號</text> </textAnnotation> <association id="association1" sourceRef="textannotation1" targetRef="signalintermediatethrowevent1"></association> </process>
<signal id="alert" name="alert"></signal> <signal id="abort" name="abort"></signal> <process id="catchSignal" name="My process" isExecutable="true"> <startEvent id="startevent1" name="Start"></startEvent> <userTask id="usertask1" name="附加邊界用戶任務"></userTask> <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow> <intermediateCatchEvent id="signalintermediatecatchevent1" name="SignalCatchEvent"> <signalEventDefinition signalRef="abort"></signalEventDefinition> </intermediateCatchEvent> <sequenceFlow id="flow2" sourceRef="startevent1" targetRef="signalintermediatecatchevent1"></sequenceFlow> <userTask id="usertask2" name="被中間信號拋出事件觸發"></userTask> <sequenceFlow id="flow3" name="捕獲abort信號" sourceRef="signalintermediatecatchevent1" targetRef="usertask2"></sequenceFlow> <endEvent id="endevent1" name="End"></endEvent> <sequenceFlow id="flow4" sourceRef="usertask2" targetRef="endevent1"></sequenceFlow> <sequenceFlow id="flow5" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow> <boundaryEvent id="boundarysignal1" name="Signal" attachedToRef="usertask1" cancelActivity="true"> <signalEventDefinition signalRef="alert"></signalEventDefinition> </boundaryEvent> <sequenceFlow id="flow6" name="捕獲alert信號" sourceRef="boundarysignal1" targetRef="usertask3"></sequenceFlow> <userTask id="usertask3" name="經過信號邊界事件觸發"></userTask> <sequenceFlow id="flow7" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow> </process>