【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就說能夠完成任務了。因此但願有明白的朋友留言給我,我也但願能從根本解決問題。~~謝謝你們

相關文章
相關標籤/搜索