(二)BPMN2.0规范介绍——4网关 Gateways
目录
一、定义
二、排他网关 Exclusive Gateway
三、并行网关 Parallel Gateway
四、包容网关 Inclusive Gateway
五、基于事件的网关 Eventbased Gateway
一、定义
网关用于管理执行流向(按照BPMN 2.0标准),涉及执行token标志的处理)。网关能够消耗和生成标志。
网关采用带有图标的菱形符号表示;该图标标识了网关的具体类型。

二、排他网关 Exclusive Gateway
- 描述:
排他网关(也叫异或网关 XOR gateway,或者更专业的,基于数据的排他网关 exclusive databased gateway),用于为流程中的决策建模。当执行到达这个网关时,所有出口顺序流会按照它们定义的顺序进行计算。条件计算为true的顺序流(当没有设置条件时,认为顺序流定义为true)会被选择用于继续流程。
请注意这里出口顺序流的含义与BPMN 2.0中的一般情况不一样。一般情况下,所有条件计算为true的顺序流,都会被选择继续,并行执行。而使用排他网关时,只会选择一条顺序流。当多条顺序 流的条件都计算为true时,其中在XML中定义的第一条(也只有这条)会被选择,用于继续流程。如果没有可选的顺序流,会抛出异常。
- 图标:
排他式网关通常通过带有异或标识的菱形表示。其中‘X’图标代表逻辑异或(XOR)操作。
特别地,在没有附加图形符号的情况下,默认采用为排他式网关。
按照BPMN 2.0标准,在同一流程图中不得同时混用带异或标识与不带标识的菱形节点符号。

- java代码:
- xml表示:
对于排他式网关来说其XML表示方式较为直观:单行定义了该网关的XML内容而条件表达式则位于输出顺序流中通过参考条件顺序流章节可以了解到这种表达式的各种可用选项以下面的具体实例为例:

> 1. <exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" />
>
> 2.
>
> 3. <sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">
>
> 4. <conditionExpression xsi:type="tFormalExpression">
>
> 5. ${input == 1}
>
> 6. </conditionExpression>
>
> 7. </sequenceFlow>
>
> 8.
>
> 9. <sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">
>
> 10. <conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>
>
> 11. </sequenceFlow>
>
> 12.
>
> 13. <sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">
>
> 14. <conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>
>
> 15. </sequenceFlow>
>
>
>
>
> 代码解读
三、并行网关 Parallel Gateway
- 描述:
网关也可以用于对流程中并行的建模。在流程模型中引入并行的最简单的网关,就是并行网关。它可以将执行分支(fork)为多条路径,也可以合并(join)执行的多条入口路径。
并行网关的功能,基于其入口与出口顺序流:
(1)分支:所有的出口顺序流都并行执行,为每一条顺序流创建一个并行执行。
(2)合并:所有到达并行网关的并行执行,都在网关处等待,直到每一条入口顺序流都有一个执行到达。然后流程经过该合并网关继续。
请注意,如果并行网关同时具有多条入口与出口顺序流,可以同时具有分支与合并的行为。在这种情况下,网关首先合并所有入口顺序流,然后分裂为多条并行执行路径。
与其他网关类型的重要区别,是并行网关不计算条件。如果连接到并行网关的顺序流上定义了条件,条件会被简单地忽略。
- 图标:
并行网关,用内部带有’加号’图标的网关(菱形)表示,代表与(AND)的含义。

- java代码:
在上面的例子中,当流程启动后,会创建两个任务:
> 1. ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
>
> 2. TaskQuery query = taskService.createTaskQuery()
>
> 3. .processInstanceId(pi.getId())
>
> 4. .orderByTaskName()
>
> 5. .asc();
>
> 6. List<Task> tasks = query.list();
>
> 7. assertEquals(2, tasks.size());
>
> 8. Task task1 = tasks.get(0);
>
> 9. assertEquals("Receive Payment", task1.getName());
>
> 10. Task task2 = tasks.get(1);
>
> 11. assertEquals("Ship Order", task2.getName());
>
>
>
>
> 代码解读
完成这两个任务后, 第二个并行网关将整合这两个执行, 因为只有一个出口顺序流, 这将不会生成任何并行执行路径, 因此只会触发ArchiveOrder(存档订单)任务.
请注意, 并行网关不需要平衡(即对应的并行网关其入口/出口顺序流的数量不需要匹配). 并行网关将等待所有入口顺序流完成, 并根据每一条出口顺序流创建相应的并行执行流程, 这一行为不受BPMN 2.0流程模型中的其他结构影响.
因此以下流程在BPMN 2.0中是合法的:

- xml表示:
定义并行网关需要一行XML:
> 1. <parallelGateway id="myParallelGateway" />
>
> 2.
>
> 3. 实际行为(分支,合并或两者皆有),由连接到该并行网关的顺序流定义。
>
> 4. 例如,上面的模型表现为下面的XML:
>
> 5.
>
> 6. <startEvent id="theStart" />
>
> 7. <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
>
> 8. <parallelGateway id="fork" />
>
> 9. <sequenceFlow sourceRef="fork" targetRef="receivePayment" />
>
> 10. <sequenceFlow sourceRef="fork" targetRef="shipOrder" />
>
> 11. <userTask id="receivePayment" name="Receive Payment" />
>
> 12. <sequenceFlow sourceRef="receivePayment" targetRef="join" />
>
> 13. <userTask id="shipOrder" name="Ship Order" />
>
> 14. <sequenceFlow sourceRef="shipOrder" targetRef="join" />
>
> 15. <parallelGateway id="join" />
>
> 16. <sequenceFlow sourceRef="join" targetRef="archiveOrder" />
>
> 17. <userTask id="archiveOrder" name="Archive Order" />
>
> 18. <sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
>
> 19. <endEvent id="theEnd" />
>
>
>
>
> 代码解读
四、包容网关 Inclusive Gateway
- 描述:
包容网关可被视作排他网关与并行网关的组合。与排他网关一样,可以在出口顺序流上定义条件,包容网关会计算它们。然而主要的区别是,包容网关与并行网关一样,可以选择多于一条(出口)顺序流。
包容网关的功能,基于其入口与出口顺序流:
(1)分支:所有出口顺序流的条件都会被计算,对于条件计算为true的顺序流,流程会并行地沿其继续,为每一条顺序流创建一个并行执行。
(2)合并:所有到达包容网关的并行执行,都会在网关处等待,直到每一条具有流程标志的入口顺序流,都有一个执行到达。这是与并行网关的重要区别。换句话说,包容网关只会等待将会被执行的入口顺序流。在合并后,流程穿过合并并行网关继续。
请注意,如果包容网关同时具有多条入口与出口顺序流,可以同时具有分支与合并的行为。在这种情况下,网关首先合并所有具有流程标志的入口顺序流,然后为条件计算为true的出口顺序流,分裂为多条并行执行路径
- 图标:
包容网关,用内部带有’圆圈’图标的网关(菱形)表示。

- java代码:
在示例中可以看到,在流程开始运行时如果满足以下两个条件:支付状态未完成(paymentReceived = false)以及订单已提交(shipOrder = true),系统将生成两个子任务;若只有一个条件满足则只生成一个子任务;若没有任何一个流程变量设置为true则系统将抛出异常并可指定默认队列以避免该问题。
在另一个示例中仅有一个子任务被创建即ship order(传递订单)会被执行:
> 1. HashMap<String, Object> variableMap = new HashMap<String, Object>();
>
> 2. variableMap.put("receivedPayment", true);
>
> 3. variableMap.put("shipOrder", true);
>
> 4. ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin");
>
> 5. TaskQuery query = taskService.createTaskQuery()
>
> 6. .processInstanceId(pi.getId())
>
> 7. .orderByTaskName()
>
> 8. .asc();
>
> 9. List<Task> tasks = query.list();
>
> 10. assertEquals(1, tasks.size());
>
> 11. Task task = tasks.get(0);
>
> 12. assertEquals("Ship Order", task.getName());
>
>
>
>
> 代码解读
完成该任务后,
第二个包容网关将整合这两个操作,
由于仅存在一条出口的序列流程,
无需生成多线程的执行路径,
将触发或执行该存档订单的任务。
请注意包容网关无需"平衡"(即
对应于其入口与输出序列流程数量无需相等)。
它会等待所有输入的序列流程就绪,
随后针对每个输出序列流程启动独立的执行,
这一机制完全不受流程模型中其他结构的影响。
- xml表示:
定义包容网关需要一行XML:
> 1. <inclusiveGateway id="myInclusiveGateway" />
>
> 2.
>
> 3. 实际行为(分支,合并或两者皆有),由连接到该包容网关的顺序流定义。
>
> 4. 例如,上面的模型表现为下面的XML:
>
> 5.
>
> 6. <startEvent id="theStart" />
>
> 7. <sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
>
> 8. <inclusiveGateway id="fork" />
>
> 9. <sequenceFlow sourceRef="fork" targetRef="receivePayment" >
>
> 10. <conditionExpression xsi:type="tFormalExpression">
>
> 11. ${paymentReceived == false}
>
> 12. </conditionExpression>
>
> 13. </sequenceFlow>
>
> 14. <sequenceFlow sourceRef="fork" targetRef="shipOrder" >
>
> 15. <conditionExpression xsi:type="tFormalExpression">
>
> 16. ${shipOrder == true}
>
> 17. </conditionExpression>
>
> 18. </sequenceFlow>
>
> 19. <userTask id="receivePayment" name="Receive Payment" />
>
> 20. <sequenceFlow sourceRef="receivePayment" targetRef="join" />
>
> 21. <userTask id="shipOrder" name="Ship Order" />
>
> 22. <sequenceFlow sourceRef="shipOrder" targetRef="join" />
>
> 23. <inclusiveGateway id="join" />
>
> 24. <sequenceFlow sourceRef="join" targetRef="archiveOrder" />
>
> 25. <userTask id="archiveOrder" name="Archive Order" />
>
> 26. <sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
>
> 27. <endEvent id="theEnd" />
>
>
>
>
> 代码解读
五、基于事件的网关 Eventbased Gateway
- 描述:
基于事件的网关,允许基于事件做选择。网关的每一条出口顺序流,都需要连接至一个捕获中间事件。当流程执行到达基于事件的网关时,网关类似等待状态地动作:执行被暂停。并且,为每一条出口顺序流,创建一个事件订阅。
请注意基于事件的网关,其出口顺序流与一般的顺序流不同。这些顺序流从不实际被执行。相反,它们允许流程引擎决定,当执行到达一个基于事件的网关时,需要订阅什么事件。基于下列约束:
(1)一个基于事件的网关,必须有两条或更多的出口顺序流。
(2)基于事件的网关,只能连接至 intermediateCatchEvent(捕获中间事件) 类型的元素(Activiti不支持基于事件的网关后,连接接收任务,Receive Task)。
(3)连接至基于事件的网关的 intermediateCatchEvent ,必须只有一个入口顺序流。
- 图标:
基于事件的网关,用内部带有特殊图标的网关(菱形)表示。

- java代码:
- xml表示:
用于命名基于事件型网关的关键XML元素。
下述流程展示了带有基于事件型网关的操作范例。每当流程触达该类网关时就会暂停执行,并由实例订阅alert信号事件以进行关注。该流程将创建一个在10分钟后自动触发的定时器以等待此类信号的发生。
此外,在此情境下:
如果在10分钟内发生该特定信号,则会取消相关定时器并沿相应的信号路径继续执行。
如果未能及时响应则会在预定时间后自动终止当前操作并解除对该信号的关注。

> 1. <definitions id="definitions"
>
> 2. xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
>
> 3. xmlns:activiti="http://activiti.org/bpmn"
>
> 4. targetNamespace="Examples">
>
> 5. <signal id="alertSignal" name="alert" />
>
> 6. <process id="catchSignal">
>
> 7. <startEvent id="start" />
>
> 8. <sequenceFlow sourceRef="start" targetRef="gw1" />
>
> 9. <eventBasedGateway id="gw1" />
>
> 10. <sequenceFlow sourceRef="gw1" targetRef="signalEvent" />
>
> 11. <sequenceFlow sourceRef="gw1" targetRef="timerEvent" />
>
> 12. <intermediateCatchEvent id="signalEvent" name="Alert">
>
> 13. <signalEventDefinition signalRef="alertSignal" />
>
> 14. </intermediateCatchEvent>
>
> 15. <intermediateCatchEvent id="timerEvent" name="Alert">
>
> 16. <timerEventDefinition>
>
> 17. <timeDuration>PT10M</timeDuration>
>
> 18. </timerEventDefinition>
>
> 19. </intermediateCatchEvent>
>
> 20. <sequenceFlow sourceRef="timerEvent" targetRef="exGw1" />
>
> 21. <sequenceFlow sourceRef="signalEvent" targetRef="task" />
>
> 22. <userTask id="task" name="Handle alert"/>
>
> 23. <exclusiveGateway id="exGw1" />
>
> 24. <sequenceFlow sourceRef="task" targetRef="exGw1" />
>
> 25. <sequenceFlow sourceRef="exGw1" targetRef="end" />
>
> 26. <endEvent id="end" />
>
> 27. </process>
>
> 28. </definitions>
>
>
>
>
> 代码解读
