【activitiワークフロー】activiti 7におけるマルチインスタンスパラレル署名の実装

5687 ワード

併行会の署名を実現する際、奇妙な問題に遭遇し、同じ問題に遭遇しやすい友人が迅速に問題を解決することを記録した.
問題の起源
まず、公式ドキュメントでは、マルチインスタンスの使用方法について説明します.以下は、公式に提供されているsampleです.

  
    ${nrOfCompletedInstances/nrOfInstances >= 0.6 }
  

上のコードを説明すると、assigneeListは集合であり、例えば["kermit"、"gonzo"、"fozzie"];activiti:elementVariable=「assignee」はloopの値を受信する変数名である.activiti:assignee=「${assignee}」は、loopで取得した変数オブジェクトとして認知者を指定することに相当し、javaでforeachと差が少ないという意味です.nrOfInstances:インスタンスの合計nrOfActiveInstances:現在のアクティビティ(すなわち、まだ完了していない)インスタンスの数.シーケンスマルチインスタンスの場合、これは常に1になります.nrOfCompletedInstances:完了したインスタンスの数.この3つの変数は、現在実行されている親実行に存在することに注意してください.${nrOfCompletedInstances/nrOfInstances>=0.6}は、言うまでもなく、変更実行が完了する量が60%以上であれば、そのノードを介して次のノードに入ることができることを意味する.
この部分全体がサインを完成させる雛形です.60%が完了すれば、ほとんどが通過すると思います(ここでの通過は、このノードのタスクを完了することであり、ビジネス上の通過とは異なります).次の段階に入ることができます.
公式サイトはここまでしか書かれていません.具体的にはactivitiユーザーマニュアル---8.5.14を参照してください.マルチインスタンス(各)
そして問題が発生しました.上記の構成を参照すると、nrOfCompletedInstancesは常に0であることがわかりました.したがって,ループ停止をトリガする条件は全くない.
トレースコードにより,ループ中のノードがcompleteされた後,ParallelMultiInstanceBehaviorというクラスのleave(DelegateExecution execution)メソッドを通過することが分かった.
コードの一部
/**
   * 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の方法を見てみましょう.
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の変数値を現在の変数に配置します.

   
        
        
            
     
   
  
    ${nrOfCompletedInstances/nrOfInstances >= 0.6 }
  

リスニングで値を変更します
@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に責任を果たすことができるとは言えません.だから分かる友达の伝言があって私にあげることを望んで、私も根本的に问题を解决することができることを望みます.~~ありがとうございます