网关用来控制流程的流向
- 排他网关ExclusiveGateway
- 并行网关ParallelGateway
- 包含网关InclusiveGateway
- 事件网关EventGateway
1.排他网关
什么是排他网关:
排他网关,用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支,
注意:排他网关只会选择一个为true的分支执行。如果有两个分支条件都为true,排他网关会选择id值较小的一条分支去执行。
为什么要用排他网关?
不用排他网关也可以实现分支,如:在连线的condition条件上设置分支条件。
在连线设置condition条件的缺点:如果条件都不满足,流程就结束了(是异常结束)。
如果 使用排他网关决定分支的走向,如下:

最终只会选择一个分支去走的流程
如果从网关出去的线所有条件都不满足则系统抛出异常(连线出现此问题会导致流程异常结束)
如果都满足选择id值较小的一条分支去执行
java
org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway 'exclusivegateway1' could be selected for continuing the process
at org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)
排他网关图标,红框内:

测试源码文件:
evection-exclusive.bpmn
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1586429287373" name="" targetNamespace="http://www.activiti.org/testm1783389563673"
typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="exclusive" isClosed="false" isExecutable="true" name="出差流程-排他" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="tom" activiti:exclusive="true" id="_3" name="填写出差单"/>
<sequenceFlow id="_4" sourceRef="_2" targetRef="_3"/>
<userTask activiti:assignee="jerry" activiti:exclusive="true" id="_5" name="部门经理审批"/>
<sequenceFlow id="_6" sourceRef="_3" targetRef="_5"/>
<userTask activiti:assignee="jack" activiti:exclusive="true" id="_7" name="总经理审批"/>
<userTask activiti:assignee="rose" activiti:exclusive="true" id="_9" name="财务审批"/>
<sequenceFlow id="_11" sourceRef="_7" targetRef="_9"/>
<endEvent id="_12" name="EndEvent"/>
<sequenceFlow id="_13" sourceRef="_9" targetRef="_12"/>
<exclusiveGateway gatewayDirection="Unspecified" id="_14" name="出差天数判断"/>
<sequenceFlow id="_15" sourceRef="_5" targetRef="_14"/>
<sequenceFlow id="_16" name="出差天数等于3天" sourceRef="_14" targetRef="_7">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${evection.num>=3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_8" name="出差天数小于3天" sourceRef="_14" targetRef="_9">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${evection.num<3}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="exclusive">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="55.0" y="100.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="55.0" width="85.0" x="150.0" y="90.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<omgdc:Bounds height="55.0" width="85.0" x="315.0" y="90.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<omgdc:Bounds height="55.0" width="85.0" x="620.0" y="135.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9">
<omgdc:Bounds height="55.0" width="85.0" x="620.0" y="300.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_12" id="Shape-_12">
<omgdc:Bounds height="32.0" width="32.0" x="805.0" y="310.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_14" id="Shape-_14" isMarkerVisible="false">
<omgdc:Bounds height="32.0" width="32.0" x="345.0" y="205.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_9" targetElement="_12">
<omgdi:waypoint x="705.0" y="327.5"/>
<omgdi:waypoint x="805.0" y="326.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_5" targetElement="_14">
<omgdi:waypoint x="361.0" y="145.0"/>
<omgdi:waypoint x="361.0" y="205.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_14" targetElement="_7">
<omgdi:waypoint x="377.0" y="221.0"/>
<omgdi:waypoint x="620.0" y="162.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_4" id="BPMNEdge__4" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="87.0" y="116.0"/>
<omgdi:waypoint x="150.0" y="117.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_3" targetElement="_5">
<omgdi:waypoint x="235.0" y="117.5"/>
<omgdi:waypoint x="315.0" y="117.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_14" targetElement="_9">
<omgdi:waypoint x="377.0" y="221.0"/>
<omgdi:waypoint x="620.0" y="327.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_7" targetElement="_9">
<omgdi:waypoint x="662.5" y="190.0"/>
<omgdi:waypoint x="662.5" y="300.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
java
import com.activiti.Evection;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class ActivitiGatewayExclusive {
/**
* 部署流程定义
*/
@Test
public void testDeployment(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用RepositoryService进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/evection-exclusive.bpmn") // 添加bpmn资源
// .addClasspathResource("bpmn/evection.png") // 添加png资源
.name("出差申请流程-排他网关")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
/**
* 启动流程实例,设置流程变量的值
*/
@Test
public void startProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义key
String key = "exclusive";
// 创建变量集合
Map<String, Object> map = new HashMap<>();
// 创建出差pojo对象
Evection evection = new Evection();
// 设置出差天数
evection.setNum(2d);
// 定义流程变量,把出差pojo对象放入map
map.put("evection",evection);
// 启动流程实例,并设置流程变量的值(把map传入)
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey(key, map);
// 输出
System.out.println("流程实例名称="+processInstance.getName());
System.out.println("流程定义id=="+processInstance.getProcessDefinitionId());
}
@Test
public void completTask(){
// 流程定义的Key
String key = "exclusive";
// 任务负责人
String assingee = "jerry";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 查询任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assingee)
.singleResult();
if(task != null){
// 根据任务id来 完成任务
taskService.complete(task.getId());
}
}
}
2.并行网关
并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出顺序流的:
fork分支:
并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
join汇聚:
所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。
注意,如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
与其他网关的主要区别是,并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
技术经理和项目经理是两个execution分支,在act_ru_execution表有两条记录分别是技术经理和项目经理,act_ru_execution还有一条记录表示该流程实例。
待技术经理和项目经理任务全部完成,在汇聚点汇聚,通过parallelGateway并行网关。
并行网关在业务应用中常用于会签任务,会签任务即多个参与者共同办理的任务。

并行网关不会判断分支上面的条件(第一个红框出条件即使设定也会忽略),并且需要技术经理和项目都提交完成之后才会进入汇聚的节点,等都提交之后在进入排他网关内
并行网关图标,红框内:

测试源码文件:
evection-parallel.bpmn
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1586429287373" name="" targetNamespace="http://www.activiti.org/testm1783389563673"
typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="parallel" isClosed="false" isExecutable="true" name="出差申请-并行网关" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="tom" activiti:exclusive="true" id="_3" name="创建出差申请"/>
<parallelGateway gatewayDirection="Unspecified" id="_4" name="ParallelGateway"/>
<sequenceFlow id="_5" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_6" sourceRef="_2" targetRef="_3"/>
<userTask activiti:assignee="jerry" activiti:exclusive="true" id="_7" name="技术经理审批"/>
<userTask activiti:assignee="jack" activiti:exclusive="true" id="_8" name="项目经理审批"/>
<sequenceFlow id="_9" sourceRef="_4" targetRef="_7">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${evection.num>=3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_10" sourceRef="_4" targetRef="_8">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${evection.num<3}]]></conditionExpression>
</sequenceFlow>
<parallelGateway gatewayDirection="Unspecified" id="_11" name="ParallelGateway"/>
<sequenceFlow id="_12" sourceRef="_7" targetRef="_11"/>
<sequenceFlow id="_13" sourceRef="_8" targetRef="_11"/>
<exclusiveGateway gatewayDirection="Unspecified" id="_14" name="ExclusiveGateway"/>
<sequenceFlow id="_15" sourceRef="_11" targetRef="_14"/>
<userTask activiti:assignee="rose" activiti:exclusive="true" id="_16" name="总经理审批"/>
<sequenceFlow id="_17" sourceRef="_14" targetRef="_16">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${evection.num>=3}]]></conditionExpression>
</sequenceFlow>
<endEvent id="_18" name="EndEvent"/>
<sequenceFlow id="_19" sourceRef="_16" targetRef="_18"/>
<sequenceFlow id="_20" sourceRef="_14" targetRef="_18">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${evection.num<3}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="parallel">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="30.0" y="130.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="55.0" width="85.0" x="120.0" y="120.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
<omgdc:Bounds height="32.0" width="32.0" x="265.0" y="125.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7">
<omgdc:Bounds height="55.0" width="85.0" x="370.0" y="85.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8">
<omgdc:Bounds height="55.0" width="85.0" x="370.0" y="175.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11">
<omgdc:Bounds height="32.0" width="32.0" x="520.0" y="130.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_14" id="Shape-_14" isMarkerVisible="false">
<omgdc:Bounds height="32.0" width="32.0" x="520.0" y="225.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_16" id="Shape-_16">
<omgdc:Bounds height="55.0" width="85.0" x="445.0" y="325.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_18" id="Shape-_18">
<omgdc:Bounds height="32.0" width="32.0" x="525.0" y="465.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="_8" targetElement="_11">
<omgdi:waypoint x="455.0" y="202.5"/>
<omgdi:waypoint x="520.0" y="146.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_7" targetElement="_11">
<omgdi:waypoint x="455.0" y="112.5"/>
<omgdi:waypoint x="520.0" y="146.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_11" targetElement="_14">
<omgdi:waypoint x="536.0" y="162.0"/>
<omgdi:waypoint x="536.0" y="225.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_17" id="BPMNEdge__17" sourceElement="_14" targetElement="_16">
<omgdi:waypoint x="520.0" y="241.0"/>
<omgdi:waypoint x="485.0" y="290.0"/>
<omgdi:waypoint x="485.0" y="325.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_19" id="BPMNEdge__19" sourceElement="_16" targetElement="_18">
<omgdi:waypoint x="485.0" y="380.0"/>
<omgdi:waypoint x="485.0" y="430.0"/>
<omgdi:waypoint x="525.0" y="481.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_5" id="BPMNEdge__5" sourceElement="_3" targetElement="_4">
<omgdi:waypoint x="205.0" y="147.5"/>
<omgdi:waypoint x="265.0" y="141.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="62.0" y="146.0"/>
<omgdi:waypoint x="120.0" y="147.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_4" targetElement="_7">
<omgdi:waypoint x="297.0" y="141.0"/>
<omgdi:waypoint x="370.0" y="112.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_20" id="BPMNEdge__20" sourceElement="_14" targetElement="_18">
<omgdi:waypoint x="552.0" y="241.0"/>
<omgdi:waypoint x="600.0" y="360.0"/>
<omgdi:waypoint x="557.0" y="481.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_4" targetElement="_8">
<omgdi:waypoint x="297.0" y="141.0"/>
<omgdi:waypoint x="370.0" y="202.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
java
import com.activiti.Evection;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class ActivitiGatewayParallel {
/**
* 部署流程定义
*/
@Test
public void testDeployment(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、使用RepositoryService进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/evection-parallel.bpmn") // 添加bpmn资源
// .addClasspathResource("bpmn/evection.png") // 添加png资源
.name("出差申请流程-并行网关")
.deploy();
// 4、输出部署信息
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
/**
* 启动流程实例,设置流程变量的值
*/
@Test
public void startProcess(){
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义key
String key = "parallel";
// 创建变量集合
Map<String, Object> map = new HashMap<>();
// 创建出差pojo对象
Evection evection = new Evection();
// 设置出差天数
evection.setNum(4d);
// 定义流程变量,把出差pojo对象放入map
map.put("evection",evection);
// 启动流程实例,并设置流程变量的值(把map传入)
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey(key, map);
// 输出
System.out.println("流程实例名称="+processInstance.getName());
System.out.println("流程定义id=="+processInstance.getProcessDefinitionId());
}
/**
* 启动流程实例
*/
@Test
public void testStartProcess(){
// 1、创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、根据流程定义Id启动流程
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("parallel");
// 输出内容
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
}
@Test
public void completTask(){
// 流程定义的Key
String key = "parallel";
// 任务负责人
String assingee = "jack";
// 获取流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取taskservice
TaskService taskService = processEngine.getTaskService();
// 查询任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(assingee)
.singleResult();
if(task != null){
// 根据任务id来 完成任务
taskService.complete(task.getId());
}
}
}
当执行到并行网关数据库跟踪如下:
当前任务表:SELECT * FROM act_ru_task

上图中:有两个任务当前执行。
查询流程实例执行表:SELECT * FROM act_ru_execution

上图中,说明当前流程实例有多个分支(两个)在运行。
对并行任务的执行:
并行任务执行不分前后,由任务的负责人去执行即可。
执行技术经理任务后,查询当前任务表 SELECT * FROM act_ru_task

已完成的技术经理任务在当前任务表act_ru_task_已被删除。
在流程实例执行表:SELECT * FROM act_ru_execution有中多个分支存在且有并行网关的汇聚结点。

有并行网关的汇聚结点:说明有一个分支已经到汇聚,等待其它的分支到达。
当所有分支任务都完成,都到达汇聚结点后:
流程实例执行表:SELECT * FROM act_ru_execution,执行流程实例已经变为总经理审批,说明流程执行已经通过并行网关

总结:所有分支到达汇聚结点,并行网关执行完成。