天天看点

Activiti原理分析(二)多实例,会或签与依次审批

多实例实现会或签,依次审批

如果你去找 Activiti 的会或签解决方案,肯定会发现 Activiti 的多实例功能。

多实例就是一个节点在运行时产生多个实例,这些节点的配置大体上都是相似的,只有参数上可能有所不同,这些实例可以配置成串行执行或者并行执行。比如 UserTask 产生多个实例,每个实例只有负责人不同,会或签就是用这个实现的。

最简单的一个会签配置如下:

<!--会签配置-->
    <userTask id="someTask" name="Activiti is awesome!" activiti:assignee="${user}">
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${userList}"
                                        activiti:elementVariable="user"/>
    </userTask>      

上面的配置用伪代码表示如下:

# userList 是列表类型的流程变量
for user in userList:
    用 user 作为任务负责人(assignee)执行 UserTask      

默认情况下只有当所有的实例都完成时,这个 UserTask 才会完成。所以上面这个配置其实就是会签,所有负责人同时进行任务,等到所有任务都完成时,才能结束这个 UserTask。

需要注意的是,因为

isSequential="false"

,所以这些实例都是并行执行的,也就是这些实例都是同时产生的。如果设置为 true,这些实例则会“依次”执行,也就是第一个负责人完成任务后,第二个实例才会产生,这样依次下去,所以只要将

isSequential

设置为

true

就可以实现依次审批了:

<!--依次审批配置-->
    <userTask id="someTask" name="Activiti is awesome!" activiti:assignee="${user}">
      <multiInstanceLoopCharacteristics isSequential="true" activiti:collection="${userList}"
                                        activiti:elementVariable="user"/>
    </userTask>      

“或签”又该如何实现呢?

multiInstanceLoopCharacteristics

还支持配置结束条件,通过结束条件的配置即可实现或签:

<!--或签配置-->
        <userTask id="someTask" name="Activiti is awesome!" activiti:assignee="${user}">
            <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${userList}"
                                              activiti:elementVariable="user">
                <completionCondition>${nrOfCompletedInstances == 1}</completionCondition>
            </multiInstanceLoopCharacteristics>
        </userTask>      

completionCondition

里面填写的就是结束条件,其中

nrOfCompletedInstances

是多实例节点的内置变量,表示已经完成实例数目,除此之外还有下面几个内置变量:

  • nrOfInstances

    : 实例总数
  • nrOfCompletedInstances

    : 已完成实例总数
  • nrOfActiveInstances

    :当前活跃实例总数

通过这几个变量可以配置出更加丰富的结束条件,比如我可以配置一个 "半会签",即只要一半的人通过就行了:

<!--半会签配置-->
    <userTask id="someTask" name="Activiti is awesome!" activiti:assignee="${user}">
            <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${userList}"
                                              activiti:elementVariable="user">
                <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.5}</completionCondition>
            </multiInstanceLoopCharacteristics>
    </userTask>      

除了 UserTask 可以多实例,Activiti 上还有好多节点支持多实例,配置也都是相似的:

另外,多实例的这个概念与配置方法都是写在 BPMN 2.0 规范中的,而不是 Acitiviti 独有的,他们在 BPMN 的图形如下(在节点上有三条竖线表示并行,有三条横线表示串行):

Activiti原理分析(二)多实例,会或签与依次审批

所以使用这种配置方式,以后想切引擎也是非常方便的。

原理

多实例在代码上采用的是装饰器模式,使用

MultiInstanceActivityBehavior

里面包一个功能节点的

ActivityBehavior

,比如

UserTaskActivityBehavior

MultiInstanceActivityBehavior

的两个子类,

ParallelMultiInstanceBehavior

SequentialMultiInstanceBehavior

就分别代表并行多实例和串行多实例的逻辑。

Activiti原理分析(二)多实例,会或签与依次审批

并行的情况会给每一个实例生成一个 execution,当满足

completionCondition

时,恢复父 execution 的执行,并且删除它的所有子 execution(就是节点产生的多实例):

Activiti原理分析(二)多实例,会或签与依次审批

至于串行多实例,这整个一串实例共用一个子 execution:

Activiti原理分析(二)多实例,会或签与依次审批

如果原理部分看得比较蒙圈,建议先去看一下我的

上一篇文章

,然后再来看这里的原理就一目了然了。

参考

继续阅读