camunda_07_gateways
目標(biāo)
- 了解BPMN中常用網(wǎng)關(guān)的作用和特點(diǎn)
匯聚網(wǎng)關(guān)的注意事項(xiàng)(重要)
- 網(wǎng)關(guān)的incoming分支不推薦帶條件, 因?yàn)闂l件的evaluation都是在前置節(jié)點(diǎn)完成時計算, 并不會在匯聚時做二次計算, 所以對匯聚條件的解讀都是錯誤的.
- 我們總可以通過一個fork網(wǎng)關(guān)(帶條件)+join網(wǎng)關(guān)(不帶條件)的組合, 來實(shí)現(xiàn)帶條件的匯聚效果.
增加default ongoing分支的說明
- 如果一個節(jié)點(diǎn)(Task或Gateway)增加了一個條件分支, 記得一定要增加一個default分支, 否則流程在執(zhí)行時, 如果該條件不滿足, 流程就會報流程無法執(zhí)行的錯誤.
- Gateway 設(shè)置default ongoing分支的方法: Camunda modeler 無法通過UI設(shè)置default分支, 只能通過改寫xml設(shè)置, 方法是: 為gateway tag 增加
defaultattribute, 缺省分支線上有一個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. 普通節(jié)點(diǎn)(如task)設(shè)置缺省分支的方法很簡單, 只要path上不添加條件即為default分支. 需要說明的是, 該分支總是被執(zhí)行.

BPMN 網(wǎng)關(guān)的作用和圖標(biāo)
網(wǎng)關(guān)不是流程真正處理節(jié)點(diǎn), 是作為流程的一個控制節(jié)點(diǎn)存在, 用于流程的合并join和分支fork, 一個網(wǎng)關(guān)節(jié)點(diǎn)可以同時用于fork也可以同時用于join. Camunda 引擎并不會為網(wǎng)關(guān)生成對應(yīng)的task記錄.

排他網(wǎng)關(guān) Exclusive gateway 頁叫做 XOR gateway
- 作為fork的含義
- 只有第一個滿足條件的分支被執(zhí)行, 其他條件的分支不會被執(zhí)行.
- 如果帶條件的分支都不滿足, 則執(zhí)行缺省分支.
- 如果無后續(xù)分支可被執(zhí)行, 流程會報錯.
- 可以理解為只有一個分支獲取execution token.
- 作為join的含義
- 只要有一個前置分支到達(dá)后, 即完成合并, 流程繼續(xù)往下執(zhí)行.
包容網(wǎng)關(guān) inclusive gateway, 也叫做 OR gateway
- 作為fork的含義
- 所有滿足條件的分支都會被執(zhí)行, 每個分支都會生成execution.
- 如果帶條件的分支都不滿足, 則執(zhí)行缺省分支.
- 如果無后續(xù)分支可被執(zhí)行, 流程會報錯.
- 作為join的含義
- 要求"所有"分支都必須達(dá)網(wǎng)關(guān), 流程才會向后執(zhí)行.
并行網(wǎng)關(guān) Parallel gateway, 也叫做 AND gateway
- 作為fork的含義
- 各個后續(xù)分支會被無條件執(zhí)行.
- 作為join的含義
- 要求"所有"分支都必須達(dá)網(wǎng)關(guān), 流程才會向后執(zhí)行.
復(fù)雜網(wǎng)關(guān) Complex gateway
使用場景
- 使用代碼實(shí)現(xiàn)的join和fork獲取token的邏輯, 舉例: 如果共有5個分支合并, 如果有3個分支令牌達(dá)到, 即想流程往后執(zhí)行, 就只能使用代碼實(shí)現(xiàn)該網(wǎng)關(guān)邏輯.
事件網(wǎng)關(guān) Event gateway
使用場景
- 事件網(wǎng)關(guān)只能用于fork, 不能用于合并.
- 事件網(wǎng)關(guān)至少有兩個outgoing分支, 只能有一個 incoming 分支.
- 事件網(wǎng)關(guān)只能后接
中間catch類事件或消息接收task - 事件網(wǎng)關(guān)的多個分支, 一直處于等待狀態(tài), 直到其中一個分支的事件到達(dá), 流程才會向后執(zhí)行.
測試程序
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) -> {
// 業(yè)務(wù)邏輯
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="網(wǎng)關(guān)測試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 網(wǎng)關(guān)示例
僅附上流程, 測試java程序和運(yùn)行結(jié)果略.

<?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="網(wǎng)關(guān)測試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>

浙公網(wǎng)安備 33010602011771號