在實現並行會籤的時候,遇到了奇怪的問題,記錄一下方便遇到一樣問題的朋友快速解決問題。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就說能夠完成任務了。因此但願有明白的朋友留言給我,我也但願能從根本解決問題。~~謝謝你們