【activiti 工做流】activiti 7 中多实例并行会签的实现

在实现并行会签的时候,遇到了奇怪的问题,记录一下方便遇到一样问题的朋友快速解决问题。java

问题起源

首先,官方文档里提到如何使用多实例,如下是官方提供的sample:app

<userTask id="miTasks" name="My Task" activiti:assignee="${assignee}">
  <multiInstanceLoopCharacteristics isSequential="false"
     activiti:collection="assigneeList" activiti:elementVariable="assignee" >
    <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6 }</completionCondition>
  </multiInstanceLoopCharacteristics>
</userTask>

解释一下上面的代码,
assigneeList 为 集合,例如["kermit", "gonzo", "fozzie"];
activiti:elementVariable="assignee" 为 接收 loop 中的值的变量名;
activiti:assignee="${assignee}" 至关于将认领人指定为loop中取得的变量对象,就和java 中 foreach 差很少的意思;
nrOfInstances:实例总数
nrOfActiveInstances:当前活动(即还没有完成)实例的数量。对于顺序多实例,这将始终为1。
nrOfCompletedInstances:已完成实例的数量。
注意,这三个变量存在当前执行的父执行中。
${nrOfCompletedInstances/nrOfInstances >= 0.6 } ,意思不言而喻,就是完成改执行的量大于等于60%就能够经过该节点进入下一节点。ide

整个这段就是完成会签的雏形。若是完成了60%,我认为绝大部分经过(这里的经过是指完成这个节点任务,和业务上的经过不一样。),能够进入下一阶段。oop

官网就只写到这里。具体能够参考 activiti 用户手册--- 8.5.14。多实例(每一个)ui

而后问题出现了。我参照上列配置,发现nrOfCompletedInstances 始终为0。因此彻底没有触发中止循环的条件。debug

经过跟踪代码,发现当循环中的节点被complete 以后,会通过ParallelMultiInstanceBehavior 这个类的 leave(DelegateExecution execution) 方法code

其中一段代码xml

/**
   * Called when the wrapped {@link ActivityBehavior} calls the {@link AbstractBpmnActivityBehavior#leave(ActivityExecution)} method. Handles the completion of one of the parallel instances
   */
  public void leave(DelegateExecution execution) {

    boolean zeroNrOfInstances = false;
    if (resolveNrOfInstances(execution) == 0) {
      // Empty collection, just leave.
      zeroNrOfInstances = true;
      removeLocalLoopVariable(execution, getCollectionElementIndexVariable());
      super.leave(execution); // Plan the default leave
      execution.setMultiInstanceRoot(false);
    }

    int loopCounter = getLoopVariable(execution, getCollectionElementIndexVariable());
    int nrOfInstances = getLoopVariable(execution, NUMBER_OF_INSTANCES);
    int nrOfCompletedInstances = getLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES) + 1;
    int nrOfActiveInstances = getLoopVariable(execution, NUMBER_OF_ACTIVE_INSTANCES) - 1;

    Context.getCommandContext().getHistoryManager().recordActivityEnd((ExecutionEntity) execution, null);
    callActivityEndListeners(execution);

    if (zeroNrOfInstances) {
      return;
    }

    DelegateExecution miRootExecution = getMultiInstanceRootExecution(execution);
    if (miRootExecution != null) { // will be null in case of empty collection
      setLoopVariable(miRootExecution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances);
      setLoopVariable(miRootExecution, NUMBER_OF_ACTIVE_INSTANCES, nrOfActiveInstances);
    }
    
   .......
}

能够看到这段代码里,nrOfCompletedInstances 是经过getLoopVariable(execution, NUMBER_OF_COMPLETED_INSTANCES)取得而后+1 获得的。
那咱们猜测,这意思应该就是每次完成后,这个计数器就+1,而后存会到参数当中去,在下面的代码中setLoopVariable(miRootExecution, NUMBER_OF_COMPLETED_INSTANCES, nrOfCompletedInstances);
确实也说明他是这样的操做。对象

这样看设值应该没问题,那必定是取值有问题,而后咱们看一下getLoopVariable方法element

protected Integer getLoopVariable(DelegateExecution execution, String variableName) {
    Object value = execution.getVariableLocal(variableName);
    DelegateExecution parent = execution.getParent();
    while (value == null && parent != null) {
      value = parent.getVariableLocal(variableName);
      parent = parent.getParent();
    }
    return (Integer) (value != null ? value : 0);
  }

很明显了,先从当前的execution 中取值,若是没有,那就从父对象中取。

我在代码的任何地方都不曾配置过nrOfCompletedInstances这个变量。按理说应该value为null, 可是debug过程当中发现,value值为0!!! 这就直接到致使,每次就取的是当前execution 的值。而设置的时候,又是将值设置在了父execution 的变量当中。因此每次的这个变量值就不会改变。都是从0->1的变化。

解决问题

思路:添加监听器,在执行leave 方法前,将父execution 中的变量值,放到当前变量中。

<userTask id="miTasks" name="My Task" activiti:assignee="${assignee}">
   <extensionElements>
        <activiti:taskListener event="complete" delegateExpression="${counterSignCompleteListener}">
        </activiti:taskListener>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]>    
     </modeler:initiator-can-complete>
   </extensionElements>
  <multiInstanceLoopCharacteristics isSequential="false"
     activiti:collection="assigneeList" activiti:elementVariable="assignee" >
    <completionCondition>${nrOfCompletedInstances/nrOfInstances >= 0.6 }</completionCondition>
  </multiInstanceLoopCharacteristics>
</userTask>

而后在监听里修改值

@Component
public class CounterSignCompleteListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {

       Integer completedInstances = Integer.valueOf(String.valueOf(delegateTask.getExecution().getParent().getVariable("nrOfCompletedInstances")));
       Integer nrOfActiveInstances = Integer.valueOf(String.valueOf(delegateTask.getExecution().getParent().getVariable("nrOfActiveInstances")));

        delegateTask.setVariableLocal("nrOfCompletedInstances", completedInstances);
        delegateTask.setVariableLocal("nrOfActiveInstances", nrOfActiveInstances);

    }
}

这样在调用的时候,变量就能正常自增,就达到想要的结果了。


此次问题我决定不是最好的解决办法,由于不少细节的地方仍旧没有弄明白,我一直认为是我本身的配置出了问题才会有这样的结果,不然官网指导也不会值是给那么简单的sample就说能够完成任务了。因此但愿有明白的朋友留言给我,我也但愿能从根本解决问题。~~谢谢你们

相关文章
相关标签/搜索