目录
- 概述
- 概念
- 多实例配置
- 图形标记
- XML内容
- 界面操作
- 视频教程
BPMN2.0 中引入了多实例的概念,它是在业务流程中定义“重复”环节的一个方法,Flowable
对其予以了支持。配置为多实例的活动在流程运行时会创建多个活动实例,既可以顺序依次执行也
可以并行同时执行,效果相当于在这个活动上循环反复执行,并在满足设置的结束条件后退出循环。
BPMN 中的多种节点可以设置为多实例,从而在流程中实现各种“重复”执行的特性,满足特定的
需求场景。本章将介绍 Flowable 中的多实例的配置方法,并结合示例介绍多实例在多种常见的活动
或子流程上的应用。
概述
BPMN 中的多实例活动是实现循环的方式之一。虽然循环总是可以通过活动连接网关将后续顺
序流指向自己或前面的活动来实现,但是多实例活动是可以在某些情况下实现起来更简单。如果想
让某些特定的活动重复执行多次,我们可以将该活动设置为多实例,让其按照配置来执行相应的次
数。
概念
多实例活动是在业务流程中定义重复环节的方式。从开发角度讲,多实例相当于循环,它可以
根据给定的集合,为每个元素顺序或并行地执行某个环节,甚至是一个子流程。
所谓多实例是在一个普通的活动上添加了额外的属性定义(被称作“多实例特性”),这样活
动在运行时被执行多次。以下几种活动可以设置为多实例活动:
- 用户任务(User Task)
- 脚本任务(Script Task)
- 服务任务(Java Service Task)
- Web 服务任务(Web Service Task)
- 业务规则任务(Business Rule Task)
- 电子邮件任务(Email Task)
- 手动任务(Manual Task)
- 接收任务(Receive Task)
- (嵌入式)子流程(Embedded Sub-Process)
- 调用活动(Call Activity)
需要注意的是,网关(Gateway)和事件(Event)不能设置为多实例的。
按照 BPMN 2.0 规范的要求,在 Flowable 的设计中,为每个实例创建的执行的父执行都有如表所示的变量:
多实例的父执行内置变量
变量名 | 含义 |
---|---|
nrOfInstances | 实例总数。 |
nrOfActiveInstances | 当前活动的(尚未完成的)实例数量。对于串行多实例来说,这个值始终是 1。 |
nrOfCompletedInstances | 已经完成的实例的数量。 |
以上这三个变量值可以通过 execution.getVariable(x)方法获取。
另外,每个创建的执行都会有一个执行本地变量,如表 24.2 所示,它对于其它执行不可见,
并且不存储在流程实例级别:
多实例的子执行内置变量
变量名 | 含义 |
---|---|
loopCounter | 表示特定实例的在循环的索引值。loopCounter 变量可以使用 flowable 的 elementIndexVariable 属性重命名。 |
多实例配置
图形标记
如果一个活动被设置为多实例,则在活动底部用三条短线表示。通过短线的朝向决定多实例的
类型,三条竖线表示是并行多实例(并行执行),三条横线表示串行多实例(顺序执行)。如图所示:
XML内容
如果要将一个活动设置为多实例活动 ,需要为该活动的XML元素必须设置一个
multiInstanceLoopCharacteristics 子元素:
<multiInstanceLoopCharacteristics isSequential="false|true">
...
</multiInstanceLoopCharacteristics>
- 多实例类型的配置
其中,isSequential属性表示多实例的类型,isSequential="false"表示是并行多实例 ,
isSequential="true"表示是串行多实例。
- 多实例的数量计算
在进入活动时会计算一次多实例的数量,Flowable 提供了多种配置方法进行配置:
2.1. 使用 loopCardinality 子元素指定
这种方法是使用 loopCardinality 子元素直接指定一个数字作为多实例的数量:
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>6</loopCardinality>
</multiInstanceLoopCharacteristics>
使用这种方式时,也可以配置为执行结果为整数的表达式:
<multiInstanceLoopCharacteristics isSequential="false|true">
<loopCardinality>${nrOfOrders-nrOfCancellations}</loopCardinality>
</multiInstanceLoopCharacteristics>
2.2、使用 loopDataInputRef 子元素指定
另一种定义实例数的方法是使用 loopDataInputRef 子元素指定设置一个类型为集合的流程变量
名。对于集合中的每个元素,都会创建一个实例。另外,也可以使用 inputDataItem 子元素配置存
储集合元素的变量名(可选)。以用户任务为例,使用方式见如下的示例:
<userTask id="userTask1" name="多实例用户任务" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false">
<loopDataInputRef>assigneeList</loopDataInputRef>
<inputDataItem name="assignee" />
</multiInstanceLoopCharacteristics>
</userTask>
上面通过 loopDataInputRef 子元素指定了类型为集合的 assigneeList 流程变量,同时通过
inputDataItem 子元素设置 assignee。假设 assigneeList 变量的值包括 zhangsan、lisi、wangwu,那么
在以上的配置中,三个用户任务会同时创建(并行多实例)。并且,每个执行都会拥有一个名为
assignee 的流程变量,它会包含集合中的对应元素,在本例中用于分配用户任务。
使用这种方式配置,存在以下两个缺点:1)loopDataInputRef 和 inputDataItem 的名称不太好
记;2)根据 BPMN 2.0 格式定义,它们不能包含表达式。为了解决这个问题,Flowable 提供了下面
的第3种方式。
2.3、通过 collection 和 elementVariable 属性指定
为了解决第②种方式中存在的问题,Flowable 为 multiInstanceCharacteristics 引入了 collection 和
elementVariable 属性:
<userTask id="userTask1" name="多实例用户任务" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
flowable:collection="${myTaskUserService.getUsersOfTask()}"
flowable:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
对比一下可以看出,这里其实是使用 collection 属性替代了第2种方式的 loopDataInputRef 子
元素,使用 elementVariable 属性替代了 inputDataItem 子元素,不同之处是 collection 属性可以配置
为一个表达式,使用起来更加灵活。
需要注意的是,collection 属性会作为表达式进行解析。如果表达式执行结果为字符串而不是
集合,不论是因为本身配置的就是静态字符串值,还是表达式执行结果为字符串,这个字符串都会
被当做变量名,其变量值为实际的集合。我们看下面的示例:
<userTask id="userTask1" name="多实例用户任务" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
flowable:collection="assigneeList" flowable:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
在以上配置中,需要将集合存储在 assigneeList 流程变量中。
为了进一步说明,我们再看下一个示例:
<userTask id="userTask1" name="多实例用户任务" flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="true"
flowable:collection="${myTaskUserService.getCollectionVariableName()}"
flowable:elementVariable="assignee" >
</multiInstanceLoopCharacteristics>
</userTask>
在以上配置中,如果表达式 myTaskUserService.getCollectionVariableName()执行结果是一个字
符串值,引擎就会用这个字符串值作为变量名,获取流程变量保存的集合。
3、多实例结束条件配置
Flowable 默认在所有的实例都完成后,多实例活动才结束。 同时, Flowable 提供了
completionCondition 子元素用于配置评估是否结束多实例的表达式,这个表达式在每个实例结束时
执行一次,如果表达式计算结果为 true,则当前多实例中所有剩余的实例将被销毁,并且多实例活
动结束,流程离开当前活动继续执行;如果表达式计算结果为 false,则继续等待剩下的实例完成。
我们看下面一个示例:
<userTask id="miTasks" name=" " flowable:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false"
flowable:collection="assigneeList" flowable:elementVariable="assignee" >
<completionCondition>${nrOfCompletedInstances/nrOfInstances >=
0.5 }</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
在以上配置中,将会为 assigneeList 集合的每个元素创建一个并行的实例。当 50%的任务完成
时,其他任务就会被删除,流程继续往下执行。
界面操作
视频教程
多实例