camunda_07_gateways
目标
- 了解BPMN中常用网关的作用和特点
汇聚网关的注意事项(重要)
- 网关的incoming分支不推荐带条件, 因为条件的evaluation都是在前置节点完成时计算, 并不会在汇聚时做二次计算, 所以对汇聚条件的解读都是错误的.
- 我们总可以通过一个fork网关(带条件)+join网关(不带条件)的组合, 来实现带条件的汇聚效果.
增加default ongoing分支的说明
- 如果一个节点(Task或Gateway)增加了一个条件分支, 记得一定要增加一个default分支, 否则流程在执行时, 如果该条件不满足, 流程就会报流程无法执行的错误.
- 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>
3. 普通节点(如task)设置缺省分支的方法很简单, 只要path上不添加条件即为default分支. 需要说明的是, 该分支总是
被执行.
BPMN 网关的作用和图标
网关不是流程真正处理节点, 是作为流程的一个控制节点存在, 用于流程的合并join和分支fork, 一个网关节点可以同时用于fork也可以同时用于join. Camunda 引擎并不会为网关生成对应的task记录.
排他网关 Exclusive gateway 页叫做 XOR gateway
- 作为fork的含义
- 只有第一个满足条件的分支被执行, 其他条件的分支不会被执行.
- 如果带条件的分支都不满足, 则执行缺省分支.
- 如果无后续分支可被执行, 流程会报错.
- 可以理解为只有一个分支获取execution token.
- 作为join的含义
- 只要有一个前置分支到达后, 即完成合并, 流程继续往下执行.
包容网关 inclusive gateway, 也叫做 OR gateway
- 作为fork的含义
- 所有满足条件的分支都会被执行, 每个分支都会生成execution.
- 如果带条件的分支都不满足, 则执行缺省分支.
- 如果无后续分支可被执行, 流程会报错.
- 作为join的含义
- 要求"所有"分支都必须达网关, 流程才会向后执行.
并行网关 Parallel gateway, 也叫做 AND gateway
- 作为fork的含义
- 各个后续分支会被无条件执行.
- 作为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>