BPMN 2.0规范

11,649 阅读4分钟

BPMN 2.0 概述

BPMN 2.0(Business Process Model and Notation)

  • 是一套业务流程模型与符号建模标准

  • 精准执行的语义来描述元素操作

  • 以XML为载体,以符号可视化业务

image-20210207094448922.png

BPMN 2.0 元素

image-20210207095102428.png

image-20210207095253624.png

流对象 (Flow Object)

  • 活动(Activities)【User Task ,Service Task...】
  • 事件 (Events) 【Start Event, End Event...】
  • 网关(GateWays 【Exclusive GateWay...】

案例(电商购物工作流程模型)

image-20210207095900271.png

BPMN 2.0 -业务过程模型和符号

image-20210207100057278.png

BPMN 2.0 流程事件-事件分类

事件分类

  • 位置分类
  • 特性分类
  • 事件定义分类

image-20210207101420252.png

事件分类-按照位置分类

  • 开始事件
  • 中间事件/边界事件
  • 结束事件

事件分类-按照特性分类

  • 捕获事件(Catching)
  • 抛出事件(Throwing)

事件分类-按照定义分类

  • 定时事件
  • 错误事件
  • 信号事件
  • 消息事件
定时事件定义
  • 指定时间(timeDate)
  • 指定持续时间(timeDuration)
  • 周期执行(timeCycle)
定时开始事件

image-20210207103906227.png

定时边界事件

image-20210207104127368.png

  • Java测试代码
 private static final Logger LOGGER = LoggerFactory.getLogger(TimerEventTests.class);

    @Rule
//    public ActivitiRule activitiRule = new ActivitiRule("activiti-mysql.cfg.xml");
    public ActivitiRule activitiRule = new ActivitiRule();

    @Test
    @Deployment(resources = {"my-process-timer-boundary.bpmn20.xml"})
    public void testTimerBoundary() throws InterruptedException {
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process");

        List<Task> tasks = activitiRule.getTaskService().createTaskQuery().listPage(0, 100);
        for (Task task : tasks) {
            LOGGER.info("task.name = {}", task.getName());
        }
        LOGGER.info("task.size() = {}", tasks.size());

        Thread.sleep(1000 * 15);

        List<Task> tasks1 = activitiRule.getTaskService().createTaskQuery().listPage(0, 100);
        for (Task task : tasks1) {
            LOGGER.info("task.name = {}", task.getName());
        }
        LOGGER.info("task.size() = {}", tasks1.size());
    }
  • my-process-timer-boundary.bpmn20.xml

     <process id="my-process">
            <startEvent id="startEvent" name="startEvent"/>
            <userTask id="commonTask" name="Common Task"/>
            <boundaryEvent attachedToRef="commonTask" id="boundaryEvent" name="Timer" cancelActivity="true">
                <timerEventDefinition>
                    <timeDuration>PT5S</timeDuration><!--流程部署完5S之后-->
                </timerEventDefinition>
            </boundaryEvent>
            <userTask id="timeoutTask" name="Timeout Task"></userTask>
            <endEvent id="end1"></endEvent>
            <endEvent id="end2"></endEvent>
            <sequenceFlow sourceRef="startEvent" targetRef="commonTask"/>
            <sequenceFlow sourceRef="commonTask" targetRef="end1"/>
            <sequenceFlow sourceRef="boundaryEvent" targetRef="timeoutTask"/>
            <sequenceFlow sourceRef="timeoutTask" targetRef="end2"/>
        </process>
    
    
  • activiti.cfg.xml

        <bean id="processEngineConfiguration"
              class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
            <property name="jdbcUrl" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000;MVCC=TRUE" />
            <property name="jdbcDriver" value="org.h2.Driver" />
            <property name="jdbcUsername" value="sa" />
            <property name="jdbcPassword" value="" />
            <property name="asyncExecutorActivate" value="true"/>
            <property name="enableVerboseExecutionTreeLogging" value="true"/>
        </bean>
    
  • 执行结果

image-20210218102758888.png

BPMN 2.0 流程事件-错误事件

错误事件定义

image-20210207131816634.png

错误边界事件(reviewSalesLead.bpmn20.xml)

image-20210207132114253.png

  • reviewSalesLead.bpmn20.xml

     <error id="notEnoughInfoError" errorCode="not_enough_info"/>
    
        <process id="reviewSaledLead" name="Review sales lead">
    
            <startEvent id="theStart" activiti:initiator="initiator"/>
            <sequenceFlow id="flow1" sourceRef="theStart" targetRef="provideNewSalesLead"/>
    
            <userTask id="provideNewSalesLead" name="Provide new sales lead" activiti:assignee="${initiator}">
                <extensionElements>
                    <activiti:formProperty id="customerName" name="Customer name" type="string" required="true"/>
                    <activiti:formProperty id="potentialProfit" name="Potential profit" type="long"/>
                    <activiti:formProperty id="details" name="Details" type="string"/>
                </extensionElements>
            </userTask>
            <sequenceFlow id="flow2" sourceRef="provideNewSalesLead" targetRef="reviewSalesLeadSubProcess"/>
    
            <subProcess id="reviewSalesLeadSubProcess" name="Review sales lead">
    
                <startEvent id="subProcessStart"/>
                <sequenceFlow id="flow3" sourceRef="subProcessStart" targetRef="fork"/>
                <sequenceFlow id="flow4" sourceRef="fork" targetRef="reviewProfitability"/>
    
                <parallelGateway id="fork"/>
                <sequenceFlow id="flow5" sourceRef="fork" targetRef="reviewCustomerRating"/>
    
                <userTask id="reviewCustomerRating" name="Review customer rating" activiti:candidateGroups="accountancy"/>
                <sequenceFlow id="flow6" sourceRef="reviewCustomerRating" targetRef="subProcessEnd1"/>
    
                <endEvent id="subProcessEnd1"/>
    
                <userTask id="reviewProfitability" name="Review profitability" activiti:candidateGroups="management">
                    <documentation>
                        ${initiator} has published a new sales lead: ${customerName}. Details: ${details}
                    </documentation>
                    <extensionElements>
                        <activiti:formProperty id="notEnoughInformation" name="Do you believe this customer is profitable?"
                                               type="enum" required="true">
                            <activiti:value id="false" name="Yes"/>
                            <activiti:value id="true" name="No (= request more info)"/>
                        </activiti:formProperty>
                    </extensionElements>
                </userTask>
                <sequenceFlow id="flow7" sourceRef="reviewProfitability" targetRef="enoughInformationCheck"/>
    
                <exclusiveGateway id="enoughInformationCheck" name="Enough information?"/>
                <sequenceFlow id="flow8" sourceRef="enoughInformationCheck" targetRef="notEnoughInformationEnd">
                    <conditionExpression>${notEnoughInformation == 'true'}</conditionExpression>
                </sequenceFlow>
                <sequenceFlow id="flow9" sourceRef="enoughInformationCheck" targetRef="subProcessEnd2">
                    <conditionExpression>${notEnoughInformation == 'false'}</conditionExpression>
                </sequenceFlow>
    
                <endEvent id="subProcessEnd2"/>
                <endEvent id="notEnoughInformationEnd">
                    <errorEventDefinition errorRef="notEnoughInfoError"/>
                </endEvent>
    
            </subProcess>
            <sequenceFlow id="flow10" sourceRef="reviewSalesLeadSubProcess" targetRef="storeLeadInCrmSystem"/>
    
            <boundaryEvent attachedToRef="reviewSalesLeadSubProcess" cancelActivity="true"
                           id="catchNotEnoughInformationError">
                <errorEventDefinition errorRef="notEnoughInfoError"/>
            </boundaryEvent>
            <sequenceFlow id="flow11" sourceRef="catchNotEnoughInformationError" targetRef="provideAdditionalDetails"/>
    
            <userTask id="provideAdditionalDetails" name="Provide additional details" activiti:assignee="${initiator}">
                <documentation>Provide additional details for ${customerName}.</documentation>
                <extensionElements>
                    <activiti:formProperty id="details" name="Additional details" type="string" required="true"/>
                </extensionElements>
            </userTask>
            <sequenceFlow id="flow12" sourceRef="provideAdditionalDetails" targetRef="reviewSalesLeadSubProcess"/>
    
            <task id="storeLeadInCrmSystem" name="Store lead in CRM system"/>
            <sequenceFlow id="flow13" sourceRef="storeLeadInCrmSystem" targetRef="processEnd"/>
    
            <endEvent id="processEnd"/>
    
        </process>
    
  • BoundaryErrorEventTest

public class BoundaryErrorEventTest extends PluggableActivitiTestCase {

  @Override
  protected void setUp() throws Exception {
    super.setUp();

    // Normally the UI will do this automatically for us
    Authentication.setAuthenticatedUserId("kermit");
  }

  @Override
  protected void tearDown() throws Exception {
    Authentication.setAuthenticatedUserId(null);
    super.tearDown();
  }

  @Deployment(resources = { "reviewSalesLead.bpmn20.xml" })
  public void testReviewSalesLeadProcess() {

    // After starting the process, a task should be assigned to the
    // 'initiator' (normally set by GUI)
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("details", "very interesting");
    variables.put("customerName", "Alfresco");
    String procId = runtimeService.startProcessInstanceByKey("reviewSaledLead", variables).getId();
    Task task = taskService.createTaskQuery().taskAssignee("kermit").singleResult();
    assertEquals("Provide new sales lead", task.getName());

    // After completing the task, the review subprocess will be active
    taskService.complete(task.getId());
    Task ratingTask = taskService.createTaskQuery().taskCandidateGroup("accountancy").singleResult();
    assertEquals("Review customer rating", ratingTask.getName());
    Task profitabilityTask = taskService.createTaskQuery().taskCandidateGroup("management").singleResult();
    assertEquals("Review profitability", profitabilityTask.getName());

    // Complete the management task by stating that not enough info was
    // provided
    // This should throw the error event, which closes the subprocess
    variables = new HashMap<String, Object>();
    variables.put("notEnoughInformation", true);
    taskService.complete(profitabilityTask.getId(), variables);

    // The 'provide additional details' task should now be active
    Task provideDetailsTask = taskService.createTaskQuery().taskAssignee("kermit").singleResult();
    assertEquals("Provide additional details", provideDetailsTask.getName());

    // Providing more details (ie. completing the task), will activate the
    // subprocess again
    taskService.complete(provideDetailsTask.getId());
    List<Task> reviewTasks = taskService.createTaskQuery().orderByTaskName().asc().list();
    assertEquals("Review customer rating", reviewTasks.get(0).getName());
    assertEquals("Review profitability", reviewTasks.get(1).getName());

    // Completing both tasks normally ends the process
    taskService.complete(reviewTasks.get(0).getId());
    variables.put("notEnoughInformation", false);
    taskService.complete(reviewTasks.get(1).getId(), variables);
    assertProcessEnded(procId);
  }

}

BPMN2.0流程事件-信号消息事件

信号开始事件

image-20210218110623215.png

信号中间事件

image-20210218110840546.png

消息事件定义

image-20210218110936519.png

BPMN2.0 -流程任务

核心流程任务

image-20210218113843352.png

image-20210218114002268.png

用户任务(User Task)定义

image-20210218114109726.png

用户任务(User Task)候选人/组配置

image-20210218114231548.png

用户任务(User Task)代理人配置

image-20210218114435651.png

通过任务监听自定义配置

image-20210218114553676.png

  • 实现

image-20210218114627429.png

  • Java代码

UserTaskTests

public class UserTaskTests {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserTaskTests.class);

    @Rule
    public ActivitiRule activitiRule = new ActivitiRule();

    @Test
    @Deployment(resources = {"my-process-usertask.bpmn20.xml"})
    public void testUsertTask() {
        ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
        TaskService taskService = activitiRule.getTaskService();
        Task task = taskService.createTaskQuery().taskCandidateUser("user1").singleResult();
        LOGGER.info("user = {}", task);
        task = taskService.createTaskQuery().taskCandidateUser("user2").singleResult();
        LOGGER.info("user2 = {}", task);

        task = taskService.createTaskQuery().taskCandidateGroup("group1").singleResult();
        LOGGER.info("group1 = {}", task);
        taskService.claim(task.getId(), "user2");
        LOGGER.info("claim task.id() = {} by user2", task.getId());
        task = taskService.createTaskQuery().taskCandidateOrAssigned("user1").singleResult();
        LOGGER.info("find by user1 task = {}", task);
        task = taskService.createTaskQuery().taskCandidateOrAssigned("user1").singleResult();
        LOGGER.info("find by user2 task = {}", task);
    }

    @Test
    @Deployment(resources = {"my-process-usertask2.bpmn20.xml"})
    public void testUserTask2() {
        ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
        TaskService taskService = activitiRule.getTaskService();
        Task task = taskService.createTaskQuery().taskCandidateUser("user1").singleResult();
        LOGGER.info("load by user task = {}", task);
        taskService.complete(task.getId());

    }
}

my-process-usertask2.bpmn20.xml

 <process id="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <userTask id="someTask" name="User Task">
            <extensionElements>
                <activiti:taskListener event="create"
                                       class="com.imooc.activiti.example.MyTaskListener"/>
                <activiti:taskListener event="complete"
                                       class="com.imooc.activiti.example.MyTaskListener"/>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

MyTaskListener.java

public class MyTaskListener implements TaskListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyTaskListener.class);

    @Override
    public void notify(DelegateTask delegateTask) {
        String eventName = delegateTask.getEventName();
        if (StringUtils.equals("create", eventName)) {
            LOGGER.info("config by listener");
            delegateTask.addCandidateUsers(Lists.newArrayList("user1", "user2"));
            delegateTask.addCandidateGroup("group1");
            delegateTask.setVariable("key1", "value1");
            delegateTask.setDueDate(DateTime.now().plusDays(3).toDate());
        } else if (StringUtils.equals("complete", eventName)) {
            LOGGER.info("task complete");
        }
    }
}

执行结果

image-20210218125222418.png

image-20210218125257031.png

BPMN2.0脚本任务

脚本任务(Script Task)

  • JUEL 脚本(默认)
  • Groovy脚本 (依赖 groovy-all.jar)
  • JavaScript 脚本

image-20210218164523473.png

脚本任务(Script Task)内置变量

image-20210218164939693.png

脚本任务(Script Task)设置返回值

image-20210218165147846.png

image-20210218165256470.png

使用groovy脚本

my-process-scripttask1.bpmn20.xml

 <process id="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <scriptTask id="someTask" name="Script Task" scriptFormat="groovy">
            <script>
                def myValue = "value123"
                execution.setVariable("myKey",myValue)
            </script>
        </scriptTask>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

testScriptTask

 @Test
    @Deployment(resources = {"my-process-scripttask1.bpmn20.xml"})
    public void testScriptTask() {
        ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");
        List<HistoricVariableInstance> historicVariableInstanceList = activitiRule.getHistoryService().createHistoricVariableInstanceQuery()
                .processInstanceId(processInstance.getId())
                .orderByVariableName().asc().listPage(0, 100);
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstanceList) {
            LOGGER.info("variable = {}", historicVariableInstance);
        }
        LOGGER.info("variables.size() = {}", historicVariableInstanceList.size());
    }

运行结果

image-20210218175135024.png

my-process-scripttask2.bpmn20.xml

 <process id="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <scriptTask id="someTask" name="Script Task" scriptFormat="juel" activiti:resultVariable="mySum">
            <script>
                #{key1 + key2}
            </script>
        </scriptTask>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

testScriptTask2

 @Test
    @Deployment(resources = {"my-process-scripttask2.bpmn20.xml"})
    public void testScriptTask2() {
        Map<String, Object> variables = Maps.newHashMap();
        variables.put("key1", 3);
        variables.put("key2", 5);
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process", variables);
        List<HistoricVariableInstance> historicVariableInstanceList = activitiRule.getHistoryService().createHistoricVariableInstanceQuery()
                .processInstanceId(processInstance.getId())
                .orderByVariableName().asc().listPage(0, 100);
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstanceList) {
            LOGGER.info("variable = {}", historicVariableInstance);
        }
        LOGGER.info("variables.size() = {}", historicVariableInstanceList.size());
    }

运行结果

image-20210218175351030.png

my-process-scripttask3.bpmn20.xml

 <process id="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <scriptTask id="someTask" name="Script Task" scriptFormat="javascript"
                    activiti:resultVariable="mySum">
            <script>
                key1 + key2
            </script>
        </scriptTask>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

testScriptTask3

    @Test
    @Deployment(resources = {"my-process-scripttask3.bpmn20.xml"})
    public void testScriptTask3() {
        Map<String, Object> variables = Maps.newHashMap();
        variables.put("key1", 3);
        variables.put("key2", 5);
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process", variables);
        List<HistoricVariableInstance> historicVariableInstanceList = activitiRule.getHistoryService().createHistoricVariableInstanceQuery()
                .processInstanceId(processInstance.getId())
                .orderByVariableName().asc().listPage(0, 100);
        for (HistoricVariableInstance historicVariableInstance : historicVariableInstanceList) {
            LOGGER.info("variable = {}", historicVariableInstance);
        }
        LOGGER.info("variables.size() = {}", historicVariableInstanceList.size());
    }

运行结果

image-20210218175605309.png

image-20210218175718023.png

BPMN 2.0 服务任务 (Java Service Task)

image-20210218180651607.png

服务任务(Java Service Task)执行Java程序的方法

  • 执行实现JavaDelegate或ActivitiBehavior的类
  • 执行JavaDelegate对象表达式,通常是Spring配置Bean
  • 执行调用方法表达式和值表达式

执行实现JavaDelegate或ActivitiBehavior的类

image-20210218181120406.png

my-process-servicetask1.bpmn20.xml

    <process id="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <serviceTask id="someTask" name="User Task"
                  activiti:class="com.imooc.activiti.example.MyJavaDelegate"/>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

testServiceTask

 @Test
    @Deployment(resources = {"my-process-servicetask1.bpmn20.xml"})
    public void testServiceTask() {
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process");
        List<HistoricActivityInstance> historicActivityInstances = activitiRule.getHistoryService()
                .createHistoricActivityInstanceQuery()
                .orderByHistoricActivityInstanceEndTime()
                .asc().listPage(0, 100);
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            LOGGER.info("activiti = {}", historicActivityInstance);
        }
    }

运行结果

image-20210218183412964.png

testServiceTask2

 @Test
    @Deployment(resources = {"my-process-servicetask2.bpmn20.xml"})
    public void testServiceTask2() {
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("mu-process");
        List<HistoricActivityInstance> historicActivityInstances = activitiRule.getHistoryService()
                .createHistoricActivityInstanceQuery()
                .orderByHistoricActivityInstanceEndTime()
                .asc().listPage(0, 100);
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            LOGGER.info("activiti = {}", historicActivityInstance);
        }
        Execution execution = activitiRule.getRuntimeService()
                .createExecutionQuery()
                .activityId("someTask")
                .singleResult();
        LOGGER.info("execution = {}", execution);
        ManagementService managementService = activitiRule.getManagementService();
        managementService.executeCommand((CommandContext commandContext) -> {
            ActivitiEngineAgenda agenda = commandContext.getAgenda();
            agenda.planTakeOutgoingSequenceFlowsOperation(
                    (ExecutionEntity) execution, false);
            return null;
        });
        historicActivityInstances = activitiRule.getHistoryService()
                .createHistoricActivityInstanceQuery()
                .orderByHistoricActivityInstanceEndTime()
                .asc().listPage(0, 100);
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
            LOGGER.info("activiti = {}", historicActivityInstance);
        }
    }

my-process-servicetask2.bpmn20.xml

  <process id="my-process">

        <startEvent id="start"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask"/>

        <serviceTask id="someTask" name="User Task"
                  activiti:class="com.imooc.activiti.example.MyActivitiBehavior"/>
        <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end"/>

        <endEvent id="end"/>

    </process>

JavaDelegate注入属性

image-20210218184224349.png

BPMN2.0顺序流和网关

image-20210218191520054.png

image-20210218191653108.png

image-20210218191754799.png

image-20210218191833833.png

image-20210218193232297.png

image-20210218193251950.png

my-process-exclusiveGateway1.bpmn20.xml

    <process id="my-process">
        <startEvent id="start"></startEvent>
        <exclusiveGateway id="gateway"/>
        <userTask id="task1" name="精英"/>
        <userTask id="task2" name="优秀"/>
        <userTask id="task3" name="普通"/>
        <endEvent id="end"/>
        <sequenceFlow id="flow1" sourceRef="start" targetRef="gateway"/>
        <sequenceFlow sourceRef="gateway" targetRef="task1">
            <conditionExpression>
                <![CDATA[${score>= 90}]]>
            </conditionExpression>
        </sequenceFlow>
        <sequenceFlow sourceRef="gateway" targetRef="task2">
            <conditionExpression>
                <![CDATA[${score>=75 && score<90}]]>
            </conditionExpression>
        </sequenceFlow>
        <sequenceFlow sourceRef="gateway" targetRef="task3"/>
        <sequenceFlow sourceRef="task1" targetRef="end"/>
        <sequenceFlow sourceRef="task2" targetRef="end"/>
        <sequenceFlow sourceRef="task3" targetRef="end"/>
    </process>

testExclusiveGatewayTask

    @Rule
    public ActivitiRule activitiRule = new ActivitiRule();

    @Test
    @Deployment(resources = {"my-process-exclusiveGateway1.bpmn20.xml"})
    public void testExclusiveGatewayTask() {
        Map<String, Object> variables = Maps.newHashMap();
        variables.put("score", 93);
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process", variables);
        Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
        LOGGER.info("task.name = {}", task.getName());
    }

输出结果为

image-20210218201418364.png

testExclusiveGatewayTask1

    @Test
    @Deployment(resources = {"my-process-exclusiveGateway1.bpmn20.xml"})
    public void testExclusiveGatewayTask1() {
        Map<String, Object> variables = Maps.newHashMap();
        variables.put("score", 70);
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process", variables);
        Task task = activitiRule.getTaskService().createTaskQuery().singleResult();
        LOGGER.info("task.name = {}", task.getName());
    }

输出结果

image-20210218201500592.png

并行网关

my-process-parallelGateway1.bpmn20.xml

 <process id="my-process">
        <startEvent id="start"/>
        <parallelGateway id="parallelStart"/>
        <userTask id="task1" name="确认支付"/>
        <userTask id="task2" name="确认收货"/>
        <parallelGateway id="parallelEnd"/>
        <userTask id="task3" name="订单完成"/>
        <endEvent id="end"/>

        <sequenceFlow sourceRef="start" targetRef="parallelStart"/>
        <sequenceFlow sourceRef="parallelStart" targetRef="task1"/>
        <sequenceFlow sourceRef="parallelStart" targetRef="task2"/>
        <sequenceFlow sourceRef="task1" targetRef="parallelEnd"/>
        <sequenceFlow sourceRef="task2" targetRef="parallelEnd"/>
        <sequenceFlow sourceRef="parallelEnd" targetRef="task3"/>
        <sequenceFlow sourceRef="task3" targetRef="end"/>
    </process>

testParallelGatewayTask1

@Test
    @Deployment(resources = {"my-process-parallelGateway1.bpmn20.xml"})
    public void testParallelGatewayTask1() {
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process");
        List<Task> taskList = activitiRule.getTaskService().createTaskQuery()
                .processInstanceId(processInstance.getId())
                .listPage(0, 100);
        for (Task task : taskList) {
            LOGGER.info("task.name = {}", task.getName());
        }
        LOGGER.info("taskList.size() = {}", taskList.size());
    }

image-20210218211352697.png

包容性网关

image-20210218211946829.png

基于事件的网关实例

image-20210218212122661.png