今天我们继续来聊聊流程实例。,部署之后的流程,这个还不能直接运行,例如我们部署了一个请假流程,现在 zhangsan 想要请假,他就需要开启一个请假流程,lisi 想请假,他也需要开启一个请假流程,这一个一个开启的请假流程就是流程实例,而我们一开始部署的请假流程,则类似于一个模版,基于此模版,我们可以开启很多个具体的流程实例。从这个角度来说,上篇文章我们定义的 ProcessDefinition 就类似于一个 Java 类,今天我们要介绍的 ProcessInstance 则相当于一个 Java 对象。,首先我们需要先捋清三个概念:,流程定义 ProcessDefinition 这个好说,其实就是我们上篇文章中和大家介绍的内容。将一个流程 XML 文件部署到 flowable 中,这就是一个定义好的流程了,基于这个定义好的流程,我们可以开启很多流程实例。,流程实例 ProcessInstance 就是通过流程定义启动的一个流程,他表示一个流程从开始到结束的最大的流程分支,在一个流程中,只存在一个流程实例,流程实例和流程定义的关系就类似于 Java 对象和 Java 类之间的关系。,执行实例 Execution 稍微有点难以理解。,首先从类的关系上来看,ProcessInstance 就是 Execution 的子类。,流程实例通常是执行实例的根结点,即在一个流程中,出口和入口可以算是一个流程实例的节点,而中间的过程则是执行实例。,假如流程本身就是一条线,那么流程实例和执行实例基本上是一样的,但是如果流程中包含多条线,例如下图:,,这张图中有并行网关,并行任务执行的时候,每一个并行任务就是一个执行实例,这样大家就好理解了。,结论就是,在一个流程实例中,除了开始和结束之外,其他的都是执行实例。即使流程只有一条线,中间的也都是执行实例,只不过此时的执行实例等于流程实例而已。,好啦,三个基本概念先捋清楚。,当我们将流程部署好之后,接下来启动流程,我们有五种不同的方式去启动一个流程。,首先就是通过流程定义的 id 去启动一个流程,对应的方法名称就是 RuntimeService#startProcessInstanceById,该方法有好几个重载的方法,不同的重载方法只是传递的参数不同而已,其他基本上都是一样的。,也可以通过流程定义的 key 去启动一个流程,根据上篇文章的介绍,大家知道,这个流程定义的 key 其实就是流程 XML 文件中的 id,这个对应的方法名是 RuntimeService#startProcessInstanceByKey。,有这样一种情况,例如我有两个子系统 A 和 B,A 和 B 中都有一个请假流程的定义,现在当我想要启动一个流程的时候,怎么知道是启动 A 的请假流程还是启动 B 的请假流程呢?此时我们可以通过租户 ID 即 tenantId 去区分,所以,流程启动就还有一个方法 RuntimeService#startProcessInstanceByKeyAndTenantId。,通过消息去启动一个流程,对应的方法是 RuntimeService#startProcessInstanceByMessage。,通过消息+租户 ID 去启动一个流程,对应的方法是 RuntimeService#startProcessInstanceByMessageAndTenantId。,首先我们绘制一个简单的流程图,然后按照上篇文章所介绍的方式进行部署,流程图如下:,,流程 XML 文件如下:,这个 XML 文件我跟大家说一句,在启动节点上我设置了 flowable:initiator=”INITIATOR”,相当于定义了流程发起人的变量为 INITIATOR,这个变量名是自定义的,定义好之后,将来我就可以在其他节点中就可以使用这个变量了。,很简单的流程,其中:,好了,先按照上篇文章我们介绍的方式部署流程。,接下来我们要启动流程,假设我们用流程定义的 key 来启动一个流程实例:,启动的代码其实很简单,当流程启动成功之后,流程中的每一步都会记录在 ACT_RU_EXECUTION 表中,同时,如果这个节点是一个用户任务节点(UserTask),那么同时还会在 ACT_RU_TASK 表中添加一条记录。,Authentication.setAuthenticatedUserId(“wangwu”); 表示设置流程的发起人。,另外一种设置流程发起人的方式如下:,对于我们上面的流程来说,启动之后,就会进入到提交请假申请这个节点中,所以一共走了两个节点,那么 ACT_RU_EXECUTION 表中应该有两条记录了,如下图:,,再来看看 ACT_RU_TASK 表中的内容:,,可以看到,该表中有一条记录,这条记录其实就是提交请假申请这个节点,现在流程就停在这一步了,需要用户手动操作,才会继续向下走。,从这两张表中我们也可以大致上看出来,EXECUTION 和 ProcessInstance 之间的关系,ACT_RU_EXECUTION 表中的每一条记录就是一个 EXECUTION,多个 EXECUTION 对应同一个 PROC_INST_ID_,而 ACT_RU_TASK 表中的每一条 Task 记录也都对应了一个 EXECUTION。,现在我们就先去查询 wangwu 需要完成的 Task(wangwu 是流程的发起人):,根据前面的介绍,我们知道,这个查询肯定是去 ACT_RU_TASK 表中进行查询的,我们来看下执行的 SQL:,,可以看到,这里就是根据 ASSIGNEE_ 字段去查询任务的。,查询到任务之后,接下来去完成任务:,这个表示查询到 wangwu 的任务然后完成,这个方法执行完成之后,首先会在 ACT_RU_TASK 表中插入一条新的需要 zhangsan 完成的 Task,然后会更新 ACT_RU_EXECUTION 表中对应的执行实例信息,最后再从 ACT_RU_TASK 表中删除需要 wangwu 完成的记录,这些操作是在同一个事务当中完成的。,好了,现在再去执行 test02 的查询方法,就会发现查不到了,因为没有 wangwu 需要完成的 task 了,接下来应该去查询 zhangsan 需要完成的 task。,当一个流程实例完成后,ACT_RU_TASK 和 ACT_RU_EXECUTION 表中的记录都会被删除,所以我们可以通过查询 ACT_RU_EXECUTION 表中是否还有记录,去判断一个一个流程目前是处于执行状态还是完成状态,代码如下:,最后,如果你想要去 ACT_RU_EXECUTION 表中查询执行实例也是 OK 的,方式如下:,查看执行的 SQL 如下:,可以看到,就是去 ACT_RU_EXECUTION 表中查询的。,如果我们想删除一个流程实例,操作方式如下:,注意这个是删除正在执行的流程实例信息,并不会删除历史流程信息。,可以根据执行实例的 ID 去查询活动节点的 ID,方式如下:,这里查询的其实就是 ACT_RU_EXECUTION 表,查询到的 activeActivityId 其实就是该表的 ACT_ID 字段,我们来看下查询的 SQL:,,好啦,流程实例先聊这么多,下篇文章我们继续~
© 版权声明
文章版权归作者所有,未经允许请勿转载。