上一节我们讲解了排他网关,本节我们来讲解与排他网关类似的模式的一种网关---并行网关。
通过上一篇我们了解,排他网关是对一个事件流向线的分支决策节点,决定着任务的流向。而并行网关除了有分支以外,还有聚合。下面是一个排他网关的图示:
在该流程图中,流程任务首先通过一个节点,进行决策后,分别同时执行两个流程线,然后再归到另一个节点上统一走向结束节点,其中扮演分支和聚合工作的那两个节点,都属于并行网关。
并行网关的特点就是在一个决策点将任务分支,然后同时执行多条任务线,最后再将多条任务线聚合在一起。
下面我们编写一个购物的例子,来对并行网关进行实现。
我们在原来的测试工程中并行网关的实例,首先创建一个名为“parallelGateWay”的Activiti Diagram流程图:
然后进行流程图的绘制,该图模拟了一个网上购物的流程:
这里包括了“开始”、“流程线”、“并行网关”、“用户任务”和“结束节点”。
每个节点的详情如下:
发现生成了图片信息:
然后我们编写启动流程的方法:
现在重点来了,按照上面的那张流程图,我们此时数据库中流程表中的各表数据情况如何呢?
下面将数据库中有关刚刚启动的“parallelGateWayProcess”流程的信息展示如下:
act_ru_execution(正在执行的执行对象表):
此时有一个流程实例,两个流程对象
act_hi_procinst(流程实例的历史表):
此时有一个开始节点的流程实例为历史
act_ru_task(正在执行的任务表(只有节点式UserTask的时候,该表存在数据)):
此时正在执行的有两个UserTask任务,受理人分别为买家和卖家。
act_hi_taskinst(任务历史表):
此时有4个任务历史,分别是开始节点任务(已经执行完毕),并行网关任务(已经执行完毕),
userTask1(有开始时间,没有确定结束时间),userTask2(有开始时间,没有确定结束时间)。
act_hi_actinst(所有活动节点的历史表):
目前有两个历史节点,分别是userTask1和userTask2,只有开始时间,还没有确定结束时间。
下面我们开始查看买家和卖家的待办任务:
首先执行买家的任务:
现在act_ru_execution发生了变化,执行对象userTask1被执行完了,开始执行userTask2
而act_hi_procinst记录的是整个流程的情况,目前尚未有变化。
act_ru_task正在执行的任务表中,目前正在执行的是发货和收款的活动,办理人都是卖家
act_hi_taskinst任务历史表中,有一个买家已经办理完毕(有结束时间)的付款任务,和两个卖家还没有执行的(没有结束时间)发货和收款任务:
act_hi_actinst所有活动节点的历史表中记录了三个已经办理完毕的任务,和两个办理中的任务历史:
然后执行卖家的任务:
此时任务节点到这里:
然后分别再次查询买家和卖家的待办任务:
然后我们同时先后执行买家(收货)和卖家(收款)的任务:
此时观察act_hi_procinst记录的是整个流程的情况,已经有结束时间,说明流程结束:
然后查看act_hi_actinst所有活动节点的历史表,可以看到该流程一共的历史节点有9个:
但是流程图上只有8个节点,这里怎么会有9个呢?那是因为当两个任务走向第二个并行网关时,由于执行时间上的先后,两个任务各自执行了一个并行网关进行聚合操作。
以上就是并行网关的介绍和实例。有关并行网关的特点如下:
(1)一个流程示例只有一个,执行对象有多个
(2)并行网关的功能是基于进入和外出的顺序流的:
分支(fork):并行后的所有外出顺序流。为每个顺序流都创建一个并发分支。
聚合(join):所有到达并行网关,在此等待的进入分支,直到所有进入顺序流的分支都到达之后,流程就会通过汇聚网关。
(3)并行网关的进入和外出都是使用相同节点的标识。
(4)如果同一个并行网关有多个进入和多个外出顺序流,它就同时具有分支和汇聚功能。这时网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
通过上一篇我们了解,排他网关是对一个事件流向线的分支决策节点,决定着任务的流向。而并行网关除了有分支以外,还有聚合。下面是一个排他网关的图示:
在该流程图中,流程任务首先通过一个节点,进行决策后,分别同时执行两个流程线,然后再归到另一个节点上统一走向结束节点,其中扮演分支和聚合工作的那两个节点,都属于并行网关。
并行网关的特点就是在一个决策点将任务分支,然后同时执行多条任务线,最后再将多条任务线聚合在一起。
下面我们编写一个购物的例子,来对并行网关进行实现。
我们在原来的测试工程中并行网关的实例,首先创建一个名为“parallelGateWay”的Activiti Diagram流程图:
这里包括了“开始”、“流程线”、“并行网关”、“用户任务”和“结束节点”。
每个节点的详情如下:
发现生成了图片信息:
然后我们新建一个测试类“ParallelGateWayTest”对流程进行测试:
首先编写部署流程的测试方法:
package cn.com.parallelGateWay; import java.io.InputStream; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.RepositoryService; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.DeploymentBuilder; import org.junit.Test; public class ParallelGateWayTest { //getDefaultProcessEngine方法内部会自动读取名为activiti.cfg.xml文件的配置信息 ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine(); /**部署流程定义*/ @Test public void deploymentProcessDefinition_inputStream(){ //获得上传文件的输入流 InputStream inputStreamBpmn=this.getClass().getResourceAsStream("parallelGateWay.bpmn"); InputStream inputStreamPng=this.getClass().getResourceAsStream("parallelGateWay.png"); //获取仓库服务,从类路径下完成部署 RepositoryService repositoryService=processEngine.getRepositoryService(); DeploymentBuilder deploymentBuilder=repositoryService.createDeployment();//创建一个部署对象 deploymentBuilder.name("并行网关");//添加部署的名称 deploymentBuilder.addInputStream("parallelGateWay.bpmn", inputStreamBpmn); deploymentBuilder.addInputStream("parallelGateWay.png", inputStreamPng); Deployment deployment=deploymentBuilder.deploy();//完成部署 //打印我们的流程信息 System.out.println("部署Id:"+deployment.getId()); System.out.println("部署名称Name:"+deployment.getName()); } }部署之后结果:
然后我们编写启动流程的方法:
/**启动流程引擎*/ @Test public void startProcessInstance(){ //获取流程启动Service RuntimeService runtimeService=processEngine.getRuntimeService(); //使用流程定义的key,key对应bpmn文件对应的id, //(也是act_re_procdef表中对应的KEY_字段),默认是按照最新版本启动 String processDefinitionkey="parallelGateWayProcess";//流程定义的key就是parallelGateWayProcess //获取流程实例对象 ProcessInstance processInstance=runtimeService.startProcessInstanceByKey(processDefinitionkey); System.out.println("流程实例ID:"+processInstance.getId());//流程实例ID System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());//流程定义ID }执行流程的启动:
现在重点来了,按照上面的那张流程图,我们此时数据库中流程表中的各表数据情况如何呢?
下面将数据库中有关刚刚启动的“parallelGateWayProcess”流程的信息展示如下:
act_ru_execution(正在执行的执行对象表):
此时有一个流程实例,两个流程对象
act_hi_procinst(流程实例的历史表):
此时有一个开始节点的流程实例为历史
act_ru_task(正在执行的任务表(只有节点式UserTask的时候,该表存在数据)):
此时正在执行的有两个UserTask任务,受理人分别为买家和卖家。
act_hi_taskinst(任务历史表):
此时有4个任务历史,分别是开始节点任务(已经执行完毕),并行网关任务(已经执行完毕),
userTask1(有开始时间,没有确定结束时间),userTask2(有开始时间,没有确定结束时间)。
act_hi_actinst(所有活动节点的历史表):
目前有两个历史节点,分别是userTask1和userTask2,只有开始时间,还没有确定结束时间。
下面我们开始查看买家和卖家的待办任务:
@Test public void findMyPersonalTask(){ findTask("买家"); findTask("卖家"); } /**查询当前的个人任务(实际就是查询act_ru_task表)*/ public void findTask(String assignee){ //获取事务Service TaskService taskService=processEngine.getTaskService(); List<Task> taskList=taskService.createTaskQuery()//创建任务查询对象 .taskAssignee(assignee)//指定个人任务查询,指定办理人 .list();//获取该办理人下的事务列表 if(taskList!=null&&taskList.size()>0){ for(Task task:taskList){ System.out.println("任务ID:"+task.getId()); System.out.println("任务名称:"+task.getName()); System.out.println("任务的创建时间:"+task.getCreateTime()); System.out.println("任务办理人:"+task.getAssignee()); System.out.println("流程实例ID:"+task.getProcessInstanceId()); System.out.println("执行对象ID:"+task.getExecutionId()); System.out.println("流程定义ID:"+task.getProcessDefinitionId()); System.out.println("#############################################"); } } }查询结果:
首先执行买家的任务:
@Test public void completeMyPersonalTask(){ completeTask("3407");//执行买家的任务 } /**完成我的任务 taskId为执行任务的ID*/ public void completeTask(String taskId){ TaskService taskService=processEngine.getTaskService(); taskService.complete(taskId);//完成taskId对应的任务 System.out.println("完成ID为"+taskId+"的任务"); }
现在act_ru_execution发生了变化,执行对象userTask1被执行完了,开始执行userTask2
而act_hi_procinst记录的是整个流程的情况,目前尚未有变化。
act_ru_task正在执行的任务表中,目前正在执行的是发货和收款的活动,办理人都是卖家
act_hi_taskinst任务历史表中,有一个买家已经办理完毕(有结束时间)的付款任务,和两个卖家还没有执行的(没有结束时间)发货和收款任务:
act_hi_actinst所有活动节点的历史表中记录了三个已经办理完毕的任务,和两个办理中的任务历史:
然后执行卖家的任务:
@Test public void completeMyPersonalTask(){ completeTask("3410");//执行卖家的任务 } /**完成我的任务 taskId为执行任务的ID*/ public void completeTask(String taskId){ TaskService taskService=processEngine.getTaskService(); taskService.complete(taskId);//完成taskId对应的任务 System.out.println("完成ID为"+taskId+"的任务"); }
此时任务节点到这里:
然后分别再次查询买家和卖家的待办任务:
@Test public void findMyPersonalTask(){ findTask("买家"); findTask("卖家"); }
然后我们同时先后执行买家(收货)和卖家(收款)的任务:
@Test public void completeMyPersonalTask(){ completeTask("3602");//执行买家收货的任务 completeTask("3502");//执行卖家收款的任务 }
此时观察act_hi_procinst记录的是整个流程的情况,已经有结束时间,说明流程结束:
然后查看act_hi_actinst所有活动节点的历史表,可以看到该流程一共的历史节点有9个:
但是流程图上只有8个节点,这里怎么会有9个呢?那是因为当两个任务走向第二个并行网关时,由于执行时间上的先后,两个任务各自执行了一个并行网关进行聚合操作。
以上就是并行网关的介绍和实例。有关并行网关的特点如下:
(1)一个流程示例只有一个,执行对象有多个
(2)并行网关的功能是基于进入和外出的顺序流的:
分支(fork):并行后的所有外出顺序流。为每个顺序流都创建一个并发分支。
聚合(join):所有到达并行网关,在此等待的进入分支,直到所有进入顺序流的分支都到达之后,流程就会通过汇聚网关。
(3)并行网关的进入和外出都是使用相同节点的标识。
(4)如果同一个并行网关有多个进入和多个外出顺序流,它就同时具有分支和汇聚功能。这时网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
(5)并行网关不会解析条件,即使顺序流中定义了条件,也会被忽略。
转载请注明出处:https://blog.csdn.net/acmman/article/details/79681730