参考文章:​​http://huan1993.iteye.com/blog/2249764​​ 第一部分是部署文件的大致说明,其他文章也有介绍,熟悉的可以跳过

首先部署文件中:

<userTask id="_7" name="评估" flowable:assignee="${per}">
<extensionElements>
<flowable:taskListener event="complete" class="com.taikang.sorceress.modules.workflow.listener.IdeaTaskListener"></flowable:taskListener>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" flowable:collection="pers" flowable:elementVariable="per">
<completionCondition>${multiInstance.accessCondition(execution)}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>

userTask标签中 ,flowable:assignee 表示取得multiInstanceLoopCharacteristics标签中flowable:elementVariable的值,而flowable:elementVariable的值表示flowable:collection这个审批人集合变量的每一个审批人变量;
extensionElements标签中,设置的是绑定的TaskListener;
multiInstanceLoopCharacteristics 标签中,设置的是多实例特点,其中:
isSequential属性表示是否串行,串行也就是说是否按顺序挨个儿执行。
flowable:collection是在上一个任务节点中放在map里的key值。

ExecutionListener和TaskListener以及多实例任务结束条件类
下面说一下多实例任务的分配人环节以及结束条件部分。

分配人可以像其他文章一样使用ServiceTask读取上个节点存储的审批人。我是觉得必要性不大,直接在上个任务节点把审批人的集合存到map里完成任务即可。
map.put(“pers”, Arrays.asList(pers_arr));
taskService.complete(taskId, map);
类似于这样。注意map的key和部署文件中flowable:collection的值相同即可。

然后说一下多实例任务结束条件判定部分的坑。我当时看其他文章一直不明白为什么有了结束条件类还要绑TaskListener类,同样都可以用作监听完成任务之后的回调。
关键就在于ExecutionListener与TaskListener的可复写方法notify。这个方法的参数是DelegateExecution与DelegateTask。这两个类官方API的解释是 used in JavaDelegates and ExecutionListeners以及used in JavaDelegates and DelegateListeners。而JavaDelegates是用ServiceTask分配审批人的方式,是直接在DelegateExecution的变量调用setVariable方法设置审批人的。
这两种设置审批人的方法其实都是设置在了多实例任务所处的execution里的,所以均可。

区别在于多实例任务每次每个审批人comlete了之后。
首先说一下调用顺序,当taskService.complete(taskId, map)调用完之后,如果TaskListener的监听事件设置为comlete,那么这里会先触发TaskListener中的notify方法,之后再触发结束条件类的自定义结束函数。并且多实例任务中每次complete了之后都会顺序触发这两个类中的回调函数。
这是我的结束条件判断类:

public class MultiInstanceCompleteTask implements Serializable {
/**
* 评估结果判定条件
* @param execution 分配执行实例
*/
public boolean accessCondition(DelegateExecution execution){
//已完成的实例数
int completedInstance = (int)execution.getVariable("nrOfCompletedInstances");
//否决判断,一票否决
if (execution.getVariable(“reject”) != null){
int rejectCount = (int)execution.getVariable(“reject”);
if(rejectCount > 0 ){
//输出方向为拒绝
execution.setVariable("outcome", “reject”);
//一票否决其他实例没必要做,结束
return true;
}
}
//所有实例任务未全部做完则继续其他实例任务
if(completedInstance != sum){
return false;
}else{
//输出方向为赞同
execution.setVariable("outcome",“approved”);
//所有都做完了没被否决,结束
return true;
}
}

我部署文件代码中multiInstance.accessCondition(execution)对应的便是此处。其中的mulitiInstance如果是和spring整合了,就是spring管理的bean的id,否则就是流程变量的key。

我遇到的坑在于无论你在多实例任务调用taskService.complete(taskId, map)之前往map里存了什么,在这个结束条件类里都是取不到的。
原因在于这里的回调参数是DelegateExecution类,是整体多实例任务的环境,在执行其中一个任务时是取不到的。
可以取到的类是DelegateTask类,所以我们每个实例的执行结果处理,应写在TaskListener类中,而结束条件类用作对TaskListener中的处理结果(包括各种结果的计数等)进行判断,然后在DelegateExecution的变量中设置输出方向是通过还是驳回等。这里判断函数的返回时是个boolean,它表示整个多实例任务节点是否结束,结束的意思是再进行下一个或其他多实例任务,还是将其他多实例任务短路掉直接结束,根据方法中setVariable中的值决定之后走向。也就是说boolean不代表接受或驳回,而是代表多实例任务节点是否提前结束。

另外计数变量的初值应在多实例任务节点钱的连线上绑定的ExecutionListener中设置,因为这才能作用于整个多实例任务。如果你在执行多实例任务中的某一个时是取不到的。代码如下:

public class IdeaExecutionListener implements ExecutionListener {

@Override
public void notify(DelegateExecution delegateExecution) {
delegateExecution.setVariable("unrelated",0);
delegateExecution.setVariable("rejected",0);
}
}

TaskListener示例

public class IdeaTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
//result的值为控制类中taskService.complete(taskId, map)时,map中所设
String result = (String) delegateTask.getVariable("result");
//ExecutionListner类中设置的拒绝计数变量
int rejectedCount = (int)delegateTask.getVariable(“reject”);
if(“reject”.equals(result)){
//拒绝
delegateTask.setVariable("rejected", ++rejectedCount);
}
}

另附判断结果类中流程引擎自带可用变量:
1.nrOfInstances 该会签环节中总共有多少个实例

2.nrOfActiveInstances 当前活动的实例的数量,即还没有 完成的实例数量。

3.nrOfCompletedInstances 已经完成的实例的数量