网关篇
网关
可控制流程的执行流向,常用于拆分或合并复杂的流程场景。在Activiti7中,有以下几种类型的网关:
-
排他网关(Exclusive Gateway):用于在流程中进行条件判断,根据不同的条件选择不同的分支路径。只有满足条件的分支会被执行,其他分支会被忽略。
-
并行网关(Parallel Gateway):用于将流程分成多个并行的分支,这些分支可以同时执行。当所有分支都执行完毕后,流程会继续向下执行。
-
包容网关(Inclusive Gateway):用于根据多个条件的组合情况选择分支路径。可以选择满足任意一个条件的分支执行,或者选择满足所有条件的分支执行。
-
事件网关(Event Gateway):用于根据事件的触发选择分支路径。当指定的事件触发时,流程会选择对应的分支执行。
这些网关可以根据实际需求灵活地组合使用,以实现不同的流程控制逻辑。Activiti7提供了直观的图形化界面,用户可以通过拖拽和连接网关来定义流程的分支和合并。同时,Activiti7还提供了丰富的API和扩展点,方便开发人员进行二次开发和定制。接下来我们分别介绍下各种网关的应用。
1.排他网关
排他网关(exclusive gateway)(也叫异或网关 XOR gateway,或者更专业的,基于数据的排他网关 exclusive data-based gateway),用于对流程中的决策建模。当执行到达这个网关时,会按照所有出口顺序流定义的顺序对它们进行计算。选择第一个条件计算为true的顺序流(当没有设置条件时,认为顺序流为true)继续流程。
排他网关用内部带有’X’图标的标准网关(菱形)表示,'X’图标代表异或的含义。请注意内部没有图标的网关默认为排他网关。BPMN 2.0规范不允许在同一个流程中混合使用有及没有X的菱形标志。
然后需要添加对应的排他网关
的流转条件
案例代码
/*** 流程部署操作*/@Testpublic void test1(){// 1.获取ProcessEngine对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.完成流程的部署操作 需要通过RepositoryService来完成RepositoryService repositoryService = processEngine.getRepositoryService();// 3.完成部署操作Deployment deploy = repositoryService.createDeployment().addClasspathResource("flow/gateway1.bpmn20.xml").name("排他网关").deploy(); // 是一个流程部署的行为 可以部署多个流程定义的System.out.println(deploy.getId());System.out.println(deploy.getName());}/*** 发起一个流程*/@Testpublic void test3(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();// 发起流程 需要通过 runtimeService来实现RuntimeService runtimeService = engine.getRuntimeService();// 通过流程定义ID来启动流程 返回的是流程实例对象ProcessInstance processInstance = runtimeService.startProcessInstanceById("gateway1:1:3");System.out.println("processInstance.getId() = " + processInstance.getId());System.out.println("processInstance.getDeploymentId() = " + processInstance.getDeploymentId());System.out.println("processInstance.getDescription() = " + processInstance.getDescription());}/*** 任务审批*/@Testpublic void test4(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();TaskService taskService = engine.getTaskService();List<Task> list = taskService.createTaskQuery().taskAssignee("张三").list();Map<String,Object> map = new HashMap<>();// 绑定对应的请假天数map.put("days",1);for (Task task : list) {taskService.complete(task.getId(),map);}}
2.并行网关
并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出顺序流的:
fork分支:并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。join汇聚: 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。
注意,如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
与其他网关的主要区别是,并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
案例代码
/*** 流程部署操作*/@Testpublic void test1(){// 1.获取ProcessEngine对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.完成流程的部署操作 需要通过RepositoryService来完成RepositoryService repositoryService = processEngine.getRepositoryService();// 3.完成部署操作Deployment deploy = repositoryService.createDeployment().addClasspathResource("flow/gateway2.bpmn20.xml").name("排他网关").deploy(); // 是一个流程部署的行为 可以部署多个流程定义的System.out.println(deploy.getId());System.out.println(deploy.getName());}/*** 发起一个流程*/@Testpublic void test3(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();// 发起流程 需要通过 runtimeService来实现RuntimeService runtimeService = engine.getRuntimeService();// 通过流程定义ID来启动流程 返回的是流程实例对象ProcessInstance processInstance = runtimeService.startProcessInstanceById("gateway2:1:17503");System.out.println("processInstance.getId() = " + processInstance.getId());System.out.println("processInstance.getDeploymentId() = " + processInstance.getDeploymentId());System.out.println("processInstance.getDescription() = " + processInstance.getDescription());}/*** 任务审批*/@Testpublic void test4(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();TaskService taskService = engine.getTaskService();List<Task> list = taskService.createTaskQuery().taskAssignee("boss").list();for (Task task : list) {taskService.complete(task.getId());}}
在并行网关中我们需要注意的是执行实例
的概念。
- 主流程实例:流程启动就会维护的一条记录,
ACT_RU_EXECUTION
中parent_id_
为null的记录 - 子流程实例:流程的每一步操作。都会更新子流程实例,表示当前流程的执行进度。如果进入的是并行网关。案例中的网关会产生3个子流程实例和一个主流程实例。
3.包容网关
包含网关可以看做是排他网关和并行网关的结合体。 和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析它们。 但是主要的区别是包含网关可以选择多于一条顺序流,这和并行网关一样。
包含网关的功能是基于进入和外出顺序流的:
分支: 所有外出顺序流的条件都会被解析,结果为true的顺序流会以并行方式继续执行, 会为每个顺序流创建一个分支。汇聚:所有并行分支到达包含网关,会进入等待状态, 直到每个包含流程token的进入顺序流的分支都到达。 这是与并行网关的最大不同。换句话说,包含网关只会等待被选中执行了的进入顺序流。 在汇聚之后,流程会穿过包含网关继续执行。
/*** 流程部署操作*/@Testpublic void test1(){// 1.获取ProcessEngine对象ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();// 2.完成流程的部署操作 需要通过RepositoryService来完成RepositoryService repositoryService = processEngine.getRepositoryService();// 3.完成部署操作Deployment deploy = repositoryService.createDeployment().addClasspathResource("flow/gateway3.bpmn20.xml").name("排他网关").deploy(); // 是一个流程部署的行为 可以部署多个流程定义的System.out.println(deploy.getId());System.out.println(deploy.getName());}/*** 发起一个流程*/@Testpublic void test3(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();// 发起流程 需要通过 runtimeService来实现RuntimeService runtimeService = engine.getRuntimeService();// 通过流程定义ID来启动流程 返回的是流程实例对象ProcessInstance processInstance = runtimeService.startProcessInstanceById("gateway3:1:35003");System.out.println("processInstance.getId() = " + processInstance.getId());System.out.println("processInstance.getDeploymentId() = " + processInstance.getDeploymentId());System.out.println("processInstance.getDescription() = " + processInstance.getDescription());}/*** 任务审批*/@Testpublic void test4(){ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();TaskService taskService = engine.getTaskService();List<Task> list = taskService.createTaskQuery().taskAssignee("boss").list();Map<String,Object> map = new HashMap<>();map.put("days",5);for (Task task : list) {taskService.complete(task.getId(),map);}}
4.事件网关
事件网关允许根据事件判断流向。网关的每个外出顺序流都要连接到一个中间捕获事件。 当流程到达一个基于事件网关,网关会进入等待状态:会暂停执行。与此同时,会为每个外出顺序流创建相对的事件订阅。
事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行", 相反它们让流程引擎去决定执行到事件网关的流程需要订阅哪些事件。 要考虑以下条件:
事件网关必须有两条或以上外出顺序流;
事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask)
连接到事件网关的中间捕获事件必须只有一个入口顺序流。