Activiti 7 啓動流程實例

首先,考慮下面這樣一個流程圖

主要的流程定義如下:

<process id="demo" name="demo" isExecutable="true">
    <startEvent id="sid-aee4f5b6-6b26-423d-85c3-499659fb523b"/>
    <manualTask id="sid-f10234c0-9056-4b68-8422-f967d08c1cac" activiti:exclusive="true" name="人工任務1"/>
    <manualTask id="sid-fad46cbb-9529-4685-83d1-95cf96dba9dc" activiti:exclusive="true" name="人工任務2">
        <extensionElements>
            <activiti:executionListener event="end" class="com.example.demo222.MyExecutionListener"/>
        </extensionElements>
    </manualTask>
    <userTask id="sid-7049a00c-8eb8-4018-9210-dba9ece4dcf7" name="用戶任務" activiti:assignee="zhangsan">
        <extensionElements>
            <activiti:taskListener event="complete" class="com.example.demo222.MyTaskCompleteListener"/>
        </extensionElements>
    </userTask>
    <endEvent id="sid-5be26610-d40f-4745-87a9-f20462595a45"/>
    <sequenceFlow id="sid-3b11c1ae-cdc2-4899-9014-0aa6ecc948a3" sourceRef="sid-aee4f5b6-6b26-423d-85c3-499659fb523b" targetRef="sid-f10234c0-9056-4b68-8422-f967d08c1cac"/>
    <sequenceFlow id="sid-04d1ef58-433d-4bd5-ac73-dec836ee2856" sourceRef="sid-f10234c0-9056-4b68-8422-f967d08c1cac" targetRef="sid-fad46cbb-9529-4685-83d1-95cf96dba9dc"/>
    <sequenceFlow id="sid-428c8fef-fe25-4c09-8d27-78f109f8312f" sourceRef="sid-fad46cbb-9529-4685-83d1-95cf96dba9dc" targetRef="sid-7049a00c-8eb8-4018-9210-dba9ece4dcf7"/>
    <sequenceFlow id="sid-fb1b8968-35e5-4fde-85c9-8c8dbafcf75b" sourceRef="sid-7049a00c-8eb8-4018-9210-dba9ece4dcf7" targetRef="sid-5be26610-d40f-4745-87a9-f20462595a45"/>
</process>

兩個人工任務,一個用戶任務

依賴

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter</artifactId>
    <version>7.1.0.M6</version>
</dependency>

流程執行監聽器

package com.example.demo222;

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

public class MyExecutionListener implements ExecutionListener {
    @Override
    public void notify(DelegateExecution execution) {
        throw new RuntimeException("ExecutionListener報錯了");
    }
}

任務監聽器

package com.example.demo222;

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

public class MyTaskCompleteListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        throw new RuntimeException("TaskListener報錯了");
    }
}

啓動流程

package com.example.demo222;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class DemoTest {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;

    @Test
    void deploy() {
        repositoryService.createDeployment()
                .addClasspathResource("processes/demo.bpmn20.xml")
                .name("demo")
                .key("demo")
                .tenantId("10086")
                .deploy();
    }

    @Test
    public void start() {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId("demo", "10086");
        System.out.println(processInstance);
    }
}

如此簡單的一個流程,如此簡單的代碼,我以爲流程會順利啓動成功,結果啓動失敗了

java.lang.RuntimeException: ExecutionListener報錯了
	at com.example.demo222.MyExecutionListener.notify(MyExecutionListener.java:9) ~[classes/:na]
	at org.activiti.engine.impl.delegate.invocation.ExecutionListenerInvocation.invoke(ExecutionListenerInvocation.java:34) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.delegate.invocation.DelegateInvocation.proceed(DelegateInvocation.java:35) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.delegate.invocation.DefaultDelegateInterceptor.handleInvocation(DefaultDelegateInterceptor.java:25) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.bpmn.helper.ClassDelegate.notify(ClassDelegate.java:109) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.bpmn.listener.ListenerNotificationHelper.executeExecutionListeners(ListenerNotificationHelper.java:77) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.agenda.AbstractOperation.executeExecutionListeners(AbstractOperation.java:81) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.agenda.AbstractOperation.executeExecutionListeners(AbstractOperation.java:71) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.agenda.TakeOutgoingSequenceFlowsOperation.handleActivityEnd(TakeOutgoingSequenceFlowsOperation.java:99) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.agenda.TakeOutgoingSequenceFlowsOperation.handleFlowNode(TakeOutgoingSequenceFlowsOperation.java:84) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.agenda.TakeOutgoingSequenceFlowsOperation.run(TakeOutgoingSequenceFlowsOperation.java:77) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:73) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:57) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:42) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.interceptor.TransactionContextInterceptor.execute(TransactionContextInterceptor.java:48) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:59) ~[activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47) [activiti-spring-7.1.0.M6.jar:na]
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) [spring-tx-5.3.22.jar:5.3.22]
	at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:45) [activiti-spring-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:29) [activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:44) [activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:39) [activiti-engine-7.1.0.M6.jar:na]
	at org.activiti.engine.impl.RuntimeServiceImpl.startProcessInstanceByKeyAndTenantId(RuntimeServiceImpl.java:93) [activiti-engine-7.1.0.M6.jar:na]
	at com.example.demo222.DemoTest.start(DemoTest.java:32) [test-classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_333]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_333]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_333]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_333]
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725) [junit-platform-commons-1.8.2.jar:1.8.2]
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) [junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) [junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) [junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) [junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) [junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66) ~[junit-jupiter-engine-5.8.2.jar:5.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at java.util.ArrayList.forEach(ArrayList.java:1259) ~[na:1.8.0_333]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at java.util.ArrayList.forEach(ArrayList.java:1259) ~[na:1.8.0_333]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) ~[junit-platform-engine-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) ~[junit-platform-launcher-1.8.2.jar:1.8.2]
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) ~[junit5-rt.jar:na]
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) ~[junit-rt.jar:na]
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) ~[idea_rt.jar:na]
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) ~[junit-rt.jar:na]
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) ~[junit-rt.jar:na]
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) ~[junit-rt.jar:na]

我一直以爲啓動流程和任務流轉是分開的,流程啓動以後就往後走,啓動時啓動,任務流轉是流轉,二者應該互不影響的,沒想到流程節點執行時報錯會導致流程啓動失敗。直到看了代碼,我才直到我錯了。流程啓動會一直往下執行,直到遇到一個它無法自動處理的節點(比如:User Task)才停下來。

下面通過代碼瞭解啓動流程實例的過程:

創建流程實例後返回一個ExecutionEntity,這個ExecutionEntity就是ProcessInstance

然後,將流程實例(ExecutionEntity)丟到Agenda中

往Agenda裏放的是一個ContinueProcessOperation,所以接下來看ContinueProcessOperation

本例中,整個流程有9個FlowElement

現在,程序運行到這裏,當前FlowElement(對應代碼中的currentFlowElement)是開始節點,即StartEvent

因爲它是FlowNode,所以接下來走節點的處理邏輯

默認情況下,節點是同步執行的,如果在任務定義時指定activiti:async="true",那麼將會異步執行

另外,我們還知道了,在流程執行過程中,是以同步方式調用監聽器的,具體見org.activiti.engine.impl.bpmn.listener.ListenerNotificationHelper#executeExecutionListeners

這裏涉及到行爲Behavior了,在本例中,設計到下面這幾種Behavior

Start節點對應的行爲是NoneStartEventActivityBehavior,它的行爲就是離開活動

通過往Agenda中放一個TakeOutgoingSequenceFlowsOperation來實現離開活動

org.activiti.engine.impl.agenda.TakeOutgoingSequenceFlowsOperation#leaveFlowNode

剛纔是走的FlowNode,現在再看SequenceFlow

將下一個FlowElement設置爲currentFlowElement,然後又是Context.getAgenda().planContinueProcessOperation(execution);

離開當前活動後,就來到了下一個活動,本例中下一個活動(Activity)是Manual Task

Manual Task是一個直接通過的活動

當走到第二個人工任務的時候,執行監聽器時拋異常了,於是啓動流程也失敗了。假設他沒有拋異常繼續往下走就遇到一個User Task

那麼在執行UserTaskActivityBehavior的時候,正常情況下是不會離開活動的,所以就停在這裏了

 

所以,到這裏,針對本例中的這個流程我們可以總結一下:

1、創建流程實例ExecutionEntity,放入Agenda中繼續執行

2、一個流程包含很多FlowElement,FlowElement分兩大類FlowNode和SequenceFlow。FlowNode有關聯的ActivityBehavior。

3、從當前FlowElement開始,如果是FlowNode,則執行與之關聯的行爲,如果是SequenceFlow則繼續執行

 

整個過程只有在FlowNode裏纔有可能停下來,像StartEvent和ManuTask這樣的FlowNode它們的行爲都是離開活動,遇到向UserTask這樣的纔會停下來

所以,通過源碼的學習可以得出兩個知識點:

1、啓動流程實例的過程中不僅僅是啓動就完了,它還會繼續執行活動,直到遇到一個它無法自動通過的活動時纔會停止,在這期間不拋異常纔算流程啓動成功

2、監聽器是同步執行的,如果在監聽器裏拋異常了,會影響到活動的執行。就像本例中一樣,在人工任務的完成監聽器裏拋異常導致流程實例啓動失敗

3、默認情況下,活動是同步執行的

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章