camunda_07_gateways

目标

  • 了解BPMN中常用网关的作用和特点

汇聚网关的注意事项(重要)

  1. 网关的incoming分支不推荐带条件, 因为条件的evaluation都是在前置节点完成时计算, 并不会在汇聚时做二次计算, 所以对汇聚条件的解读都是错误的.
  2. 我们总可以通过一个fork网关(带条件)+join网关(不带条件)的组合, 来实现带条件的汇聚效果.

增加default ongoing分支的说明

  1. 如果一个节点(Task或Gateway)增加了一个条件分支, 记得一定要增加一个default分支, 否则流程在执行时, 如果该条件不满足, 流程就会报流程无法执行的错误.
  2. Gateway 设置default ongoing分支的方法: Camunda modeler 无法通过UI设置default分支, 只能通过改写xml设置, 方法是: 为gateway tag 增加default attribute, 缺省分支线上有一个back slash符号(/).
    <bpmn2:exclusiveGateway id="Gateway_xor" default="Flow_default">
      <bpmn2:outgoing>Flow_amount100</bpmn2:outgoing>
      <bpmn2:outgoing>Flow_default</bpmn2:outgoing>
    </bpmn2:exclusiveGateway>

default分支示例
3. 普通节点(如task)设置缺省分支的方法很简单, 只要path上不添加条件即为default分支. 需要说明的是, 该分支总是被执行.

BPMN 网关的作用和图标

网关不是流程真正处理节点, 是作为流程的一个控制节点存在, 用于流程的合并join和分支fork, 一个网关节点可以同时用于fork也可以同时用于join. Camunda 引擎并不会为网关生成对应的task记录.

图标

排他网关 Exclusive gateway 页叫做 XOR gateway

  1. 作为fork的含义
  • 只有第一个满足条件的分支被执行, 其他条件的分支不会被执行.
  • 如果带条件的分支都不满足, 则执行缺省分支.
  • 如果无后续分支可被执行, 流程会报错.
  • 可以理解为只有一个分支获取execution token.
  1. 作为join的含义
  • 只要有一个前置分支到达后, 即完成合并, 流程继续往下执行.

包容网关 inclusive gateway, 也叫做 OR gateway

  1. 作为fork的含义
  • 所有满足条件的分支都会被执行, 每个分支都会生成execution.
  • 如果带条件的分支都不满足, 则执行缺省分支.
  • 如果无后续分支可被执行, 流程会报错.
  1. 作为join的含义
  • 要求"所有"分支都必须达网关, 流程才会向后执行.

并行网关 Parallel gateway, 也叫做 AND gateway

  1. 作为fork的含义
  • 各个后续分支会被无条件执行.
  1. 作为join的含义
  • 要求"所有"分支都必须达网关, 流程才会向后执行.

复杂网关 Complex gateway

使用场景

  • 使用代码实现的join和fork获取token的逻辑, 举例: 如果共有5个分支合并, 如果有3个分支令牌达到, 即想流程往后执行, 就只能使用代码实现该网关逻辑.

事件网关 Event gateway

使用场景

  • 事件网关只能用于fork, 不能用于合并.
  • 事件网关至少有两个outgoing分支, 只能有一个 incoming 分支.
  • 事件网关只能后接 中间catch类事件消息接收task
  • 事件网关的多个分支, 一直处于等待状态, 直到其中一个分支的事件到达, 流程才会向后执行.

测试程序

java

package javatest;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.camunda.bpm.client.ExternalTaskClient;

public class ExternalTaskTest {
	private final static Logger logger = Logger.getLogger(ExternalTaskTest.class.getName());

	private static void listenIncomingTask(ExternalTaskClient client, String taskName, Long amount) {
		client.subscribe(taskName).lockDuration(1000).handler((externalTask, externalTaskService) -> {
			// 业务逻辑
			Map<String, Object> variableMap = new HashMap<>();
			// 完成 Task
			externalTaskService.complete(externalTask, variableMap);

			// externalTaskService.fail
			logger.info(taskName + " task done");
		}).open();
	}

	private static void listenOutgoingTask(ExternalTaskClient client, String taskName) {
		client.subscribe(taskName).lockDuration(1000).handler((externalTask, externalTaskService) -> {
			// 获取流程信息
			Long amount = (Long) externalTask.getVariable("amount");
			logger.info("amount:" + amount);

			// 完成 Task
			externalTaskService.complete(externalTask);
			logger.info(taskName + " task done");
		}).open();
	}

	public static void main(String[] args) {
		logger.info("ExternalTaskClient setup");
		ExternalTaskClient client = ExternalTaskClient.create().baseUrl("http://localhost:8080/engine-rest")
				.asyncResponseTimeout(10000).build();

		listenOutgoingTask(client, "loan.A1");
		listenOutgoingTask(client, "loan.A2");
		listenOutgoingTask(client, "loan.A0");
		logger.info("Listening topics...");
	}
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.lzw</groupId>
  <artifactId>javatest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
<dependencies>
  <dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.4.3</version>
</dependency>
 
<dependency>
    <groupId>com.hrakaroo</groupId>
    <artifactId>glob</artifactId>
    <version>0.9.0</version>
</dependency>
        <dependency>
            <groupId>org.camunda.bpm</groupId>
            <artifactId>camunda-external-task-client</artifactId>
            <version>7.17.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
</dependencies>
</project>

fork流程图

流程图

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1xvrd7w" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.3.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.17.0">
  <bpmn:process id="process_xor_fork" name="网关测试1" isExecutable="true">
    <bpmn:startEvent id="Event_0vq0omt">
      <bpmn:outgoing>Flow_1456nu1</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:exclusiveGateway id="Gateway_1uuz4q8" default="Flow_a0">
      <bpmn:incoming>Flow_1456nu1</bpmn:incoming>
      <bpmn:outgoing>Flow_a1</bpmn:outgoing>
      <bpmn:outgoing>Flow_a2</bpmn:outgoing>
      <bpmn:outgoing>Flow_a0</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow_1456nu1" sourceRef="Event_0vq0omt" targetRef="Gateway_1uuz4q8" />
    <bpmn:sequenceFlow id="Flow_a1" name="${amount==1}" sourceRef="Gateway_1uuz4q8" targetRef="Activity_07wbjrr">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${amount==1}</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:serviceTask id="Activity_07wbjrr" name="A1" camunda:type="external" camunda:topic="loan.A1">
      <bpmn:incoming>Flow_a1</bpmn:incoming>
      <bpmn:outgoing>Flow_0zhprh8</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="Activity_0m749bw" name="A2" camunda:type="external" camunda:topic="loan.A2">
      <bpmn:incoming>Flow_a2</bpmn:incoming>
      <bpmn:outgoing>Flow_1ltvk8y</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="Activity_0094ryg" name="A0" camunda:type="external" camunda:topic="loan.A0">
      <bpmn:incoming>Flow_a0</bpmn:incoming>
      <bpmn:outgoing>Flow_13xn64x</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sequenceFlow id="Flow_a2" name="${amount==2}" sourceRef="Gateway_1uuz4q8" targetRef="Activity_0m749bw">
      <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${amount==2}</bpmn:conditionExpression>
    </bpmn:sequenceFlow>
    <bpmn:sequenceFlow id="Flow_a0" sourceRef="Gateway_1uuz4q8" targetRef="Activity_0094ryg" />
    <bpmn:endEvent id="Event_1l6225c">
      <bpmn:incoming>Flow_0zhprh8</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_0zhprh8" sourceRef="Activity_07wbjrr" targetRef="Event_1l6225c" />
    <bpmn:endEvent id="Event_0idkqv7">
      <bpmn:incoming>Flow_1ltvk8y</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_1ltvk8y" sourceRef="Activity_0m749bw" targetRef="Event_0idkqv7" />
    <bpmn:endEvent id="Event_1rno5kl">
      <bpmn:incoming>Flow_13xn64x</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_13xn64x" sourceRef="Activity_0094ryg" targetRef="Event_1rno5kl" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="process_xor_fork">
      <bpmndi:BPMNShape id="Event_0vq0omt_di" bpmnElement="Event_0vq0omt">
        <dc:Bounds x="142" y="182" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_1uuz4q8_di" bpmnElement="Gateway_1uuz4q8" isMarkerVisible="true">
        <dc:Bounds x="245" y="175" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_0ydt8z4_di" bpmnElement="Activity_07wbjrr">
        <dc:Bounds x="440" y="70" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="BPMNShape_1vmcikm" bpmnElement="Activity_0m749bw">
        <dc:Bounds x="440" y="160" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="BPMNShape_0gnw5e0" bpmnElement="Activity_0094ryg">
        <dc:Bounds x="440" y="250" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_1l6225c_di" bpmnElement="Event_1l6225c">
        <dc:Bounds x="662" y="92" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_0idkqv7_di" bpmnElement="Event_0idkqv7">
        <dc:Bounds x="662" y="182" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_1rno5kl_di" bpmnElement="Event_1rno5kl">
        <dc:Bounds x="662" y="272" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_1456nu1_di" bpmnElement="Flow_1456nu1">
        <di:waypoint x="178" y="200" />
        <di:waypoint x="245" y="200" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1f5owlm_di" bpmnElement="Flow_a1">
        <di:waypoint x="270" y="175" />
        <di:waypoint x="270" y="110" />
        <di:waypoint x="440" y="110" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="250" y="140" width="70" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0cppjxi_di" bpmnElement="Flow_a2">
        <di:waypoint x="295" y="200" />
        <di:waypoint x="440" y="200" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="333" y="182" width="70" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0kjoevt_di" bpmnElement="Flow_a0">
        <di:waypoint x="270" y="225" />
        <di:waypoint x="270" y="310" />
        <di:waypoint x="440" y="310" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0zhprh8_di" bpmnElement="Flow_0zhprh8">
        <di:waypoint x="540" y="110" />
        <di:waypoint x="662" y="110" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1ltvk8y_di" bpmnElement="Flow_1ltvk8y">
        <di:waypoint x="540" y="200" />
        <di:waypoint x="662" y="200" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_13xn64x_di" bpmnElement="Flow_13xn64x">
        <di:waypoint x="540" y="290" />
        <di:waypoint x="662" y="290" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

post 请求

POST http://localhost:8080/engine-rest/process-definition/key/process_xor_fork/start HTTP/1.1
Content-Type: application/json

{
    "variables": {
        "amount": {
            "value":555,
            "type":"long"
        },
        "item": {
            "value": "item-xyz"
        }
    }
}

测试输出

程序输出

join 网关示例

仅附上流程, 测试java程序和运行结果略.
流程图

<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_1xvrd7w" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.3.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.17.0">
  <bpmn:process id="process_xor_join" name="网关测试1" isExecutable="true">
    <bpmn:startEvent id="Event_1q3q8yh">
      <bpmn:outgoing>Flow_09irp9w</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:startEvent id="Event_00b5w04">
      <bpmn:outgoing>Flow_1s7e1rv</bpmn:outgoing>
      <bpmn:conditionalEventDefinition id="ConditionalEventDefinition_0ai7vtt">
        <bpmn:condition xsi:type="bpmn:tFormalExpression">${amount==1}</bpmn:condition>
      </bpmn:conditionalEventDefinition>
    </bpmn:startEvent>
    <bpmn:serviceTask id="Activity_193j4cl" name="A1" camunda:type="external" camunda:topic="loan.A1">
      <bpmn:incoming>Flow_09irp9w</bpmn:incoming>
      <bpmn:outgoing>Flow_1lvacs3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="Activity_0fuwa2j" name="A2" camunda:type="external" camunda:topic="loan.A2">
      <bpmn:incoming>Flow_1s7e1rv</bpmn:incoming>
      <bpmn:outgoing>Flow_0t7aaxk</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="Gateway_1e0191l">
      <bpmn:incoming>Flow_1lvacs3</bpmn:incoming>
      <bpmn:incoming>Flow_0t7aaxk</bpmn:incoming>
      <bpmn:outgoing>Flow_1f8yubd</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow_1lvacs3" sourceRef="Activity_193j4cl" targetRef="Gateway_1e0191l" />
    <bpmn:sequenceFlow id="Flow_0t7aaxk" sourceRef="Activity_0fuwa2j" targetRef="Gateway_1e0191l" />
    <bpmn:sequenceFlow id="Flow_09irp9w" sourceRef="Event_1q3q8yh" targetRef="Activity_193j4cl" />
    <bpmn:sequenceFlow id="Flow_1s7e1rv" name="${amount==1}" sourceRef="Event_00b5w04" targetRef="Activity_0fuwa2j" />
    <bpmn:serviceTask id="Activity_11vtbo0" name="A0" camunda:type="external" camunda:topic="loan.A0">
      <bpmn:incoming>Flow_1f8yubd</bpmn:incoming>
      <bpmn:outgoing>Flow_1hq8fo8</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sequenceFlow id="Flow_1f8yubd" sourceRef="Gateway_1e0191l" targetRef="Activity_11vtbo0" />
    <bpmn:endEvent id="Event_1p6n34p">
      <bpmn:incoming>Flow_1hq8fo8</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_1hq8fo8" sourceRef="Activity_11vtbo0" targetRef="Event_1p6n34p" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="process_xor_join">
      <bpmndi:BPMNShape id="Event_1q3q8yh_di" bpmnElement="Event_1q3q8yh">
        <dc:Bounds x="182" y="102" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="BPMNShape_1f8et6x" bpmnElement="Activity_193j4cl">
        <dc:Bounds x="320" y="80" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="BPMNShape_1ufbsl3" bpmnElement="Gateway_1e0191l" isMarkerVisible="true">
        <dc:Bounds x="475" y="135" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_1kp5erq_di" bpmnElement="Event_00b5w04">
        <dc:Bounds x="182" y="212" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="BPMNShape_087lirz" bpmnElement="Activity_0fuwa2j">
        <dc:Bounds x="320" y="190" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="BPMNShape_0hn9274" bpmnElement="Activity_11vtbo0">
        <dc:Bounds x="590" y="120" width="100" height="80" />
        <bpmndi:BPMNLabel />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_1p6n34p_di" bpmnElement="Event_1p6n34p">
        <dc:Bounds x="762" y="142" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="Flow_09irp9w_di" bpmnElement="Flow_09irp9w">
        <di:waypoint x="218" y="120" />
        <di:waypoint x="320" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1lvacs3_di" bpmnElement="Flow_1lvacs3">
        <di:waypoint x="420" y="120" />
        <di:waypoint x="448" y="120" />
        <di:waypoint x="448" y="160" />
        <di:waypoint x="475" y="160" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0t7aaxk_di" bpmnElement="Flow_0t7aaxk">
        <di:waypoint x="420" y="230" />
        <di:waypoint x="500" y="230" />
        <di:waypoint x="500" y="185" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1f8yubd_di" bpmnElement="Flow_1f8yubd">
        <di:waypoint x="525" y="160" />
        <di:waypoint x="590" y="160" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1s7e1rv_di" bpmnElement="Flow_1s7e1rv">
        <di:waypoint x="218" y="230" />
        <di:waypoint x="320" y="230" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="234" y="212" width="70" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1hq8fo8_di" bpmnElement="Flow_1hq8fo8">
        <di:waypoint x="690" y="160" />
        <di:waypoint x="762" y="160" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

参考

camunda-bpmn-网关(Gateways)

posted @ 2022-09-25 19:09  harrychinese  阅读(423)  评论(0编辑  收藏  举报