多实例活动
概览
多实例活动(multi-instance activity) 是定义业务流程中某个重复步骤的一种方式。
在编程概念中,多实例与 for each
结构等价:给定一个条目集合,对于集合中的每个条目,
都可以执行一个特定的步骤,甚至是一个完整的子流程,
执行的顺序可以是 串行(sequentially) 的也可以是 并行(parallel) 的。
多实例活动也是一个常规活动,但是需定义额外的属性,名为 multi-instance characteristics(多实例特性)
,
这样的活动在运行时可以执行多次。
下列活动可以定义为 多实例活动:
-
用户任务
-
脚本任务
-
服务任务
-
嵌入子流程
-
调用活动
多实例活动在图中显示为一个常规活动, 但是在任务或子流程元素的中下部有 并行 或 串行 标记。 三条竖线表示实例并行执行,而三条横线表示顺序执行。
活动的 XML 元素使用 multiInstanceLoopCharacteristics
子元素声明多实例特性。
<multiInstanceLoopCharacteristics isSequential="false|true">
...
</multiInstanceLoopCharacteristics>
isSequential
属性表示多实例的执行顺序。
该属性默认可以省略,默认值为 false
(并行)。
特殊变量
多实例中的每个实例的执行过程都是由同一个父执行过程创建,根据 BPMN 2.0 规范的要求,这个父执行过程有以下变量:
nrOfInstances |
实例总数。 |
nrOfActiveInstances |
当前以激活(尚未完成)的实例数。 对于串行多实例,该值始终为 1。 |
nrOfCompletedInstances |
已完成的实例数。 |
这些变量的值可以通过调用 execution.getVariable(x)
方法获取。
另外,每个创建的子执行过程中都有一个局部变量 (其他子执行过程不可见,也不在流程实例级别存储):
loopCounter |
特定实例在 for-each 循环中的索引(index)。 |
属性
如需将一个活动设置为多实例,请在画布中选择该活动,然后在 BPMN Navigator 面板中, 选择所需的实例类型:
实例数
实例数可以通过两种方式定义:
-
直接定义 — 通过设置一个 Cardinality 参数。
-
由集合定义 — 实例数等于集合大小。
当设置为 cardinality 时,可以使用表达式,表达式需要解析为一个正数,如:
${nrOfOrders-nrOfCancellations}
- 设置集合来源和集合
-
— 集合来源可以选择:表达式、 流程变量、以及用户 Provider。流程引擎会按照集合的大小创建同等数量的活动:
使用表达式可以为多实例活动传入一个集合。 表达式中可以包含一个 bean 方法的调用,方法需要返回对象列表:
${smpl_OrderService.getOrders()}
最简单的方式是使用流程变量作为集合源。 可以是实体列表、字符串列表、数字列表或任何其他对象列表。
对于用户任务,集合必须是用户名列表( 还有,此时唯一可用的 Assignee source 是 表达式。
如果集合是名为 ${usernames_item} 如果集合是名为 ${users_items.username} 可以手动编辑表达式,但是要注意。 |
最后一种方式是可以实现 UserListProvider,并提供一组用户名的列表。
参阅 用户任务 部分的 用户列表 Provider。
当 collection 设置完成后,系统会自动创建一个 (元素变量)Element variable。
这个变量在 for each
结构中扮演迭代器变量的角色。
可以根据需要重命名这个变量。
使用局部变量
假设,我们想要构建一个流程,流程中的多个执行者都会写入一个变量的值。 例如,多个老师为学生的作业打分。或者也可以是一个服务任务,需要写入某些值。
在这种情况下,应该在多实例活动中使用局部变量。 否则,每个实例都会覆盖外部变量的值。
基于输出的条件
当多实例是一个有输出的用户任务,则可以实现某种形式的 “投票”。
在这种情况下,系统会将每个用户做出的决策存储在 输出容器(outcomes container) 中,
这是一个 OutcomesContainer
类型的流程变量。
所有实例都完成后,可以在此容器中看到所有结果。
然后,可以在排他网关或包容网关的传出的顺序流上使用以下类型的完成条件:
-
任何人完成输出
-
每个人完成输出
-
没有人完成输出
例如,我们的流程中有一个多实例的用户任务,两个输出分别为 Yes
和 No
:
然后我们可以用这样的基于输出的条件,如, “每个人都说 Yes”:
补偿
多实例任务可能需要补偿。 可能冒出第一个建模的想法是这样的:
是的,这样可以,但并不是在所有情况下都有效。 这对于串行的同步任务是可以的,但在其他情况下可能会导致错误。
最好用带补偿的嵌入子流程来实现,这种模式在任何情况下都有效。
执行监听器
多实例与执行监听器结合使用会出现问题。
参阅 执行监听器。