本文分析一下并行网关的行为。并行网关本身的控制还是比较简单的,复杂的主要在于出口,直接上代码,ParallelGatewayActivityBehavior.java
public class ParallelGatewayActivityBehavior extends GatewayActivityBehavior {
public void execute(ActivityExecution execution) throws Exception {
PvmActivity activity = execution.getActivity();
List<PvmTransition> outgoingTransitions = execution.getActivity().getOutgoingTransitions();
execution.inactivate();
lockConcurrentRoot(execution);
List<ActivityExecution> joinedExecutions = execution.findInactiveConcurrentExecutions(activity);
int nbrOfExecutionsToJoin = execution.getActivity().getIncomingTransitions().size();
int nbrOfExecutionsJoined = joinedExecutions.size();
Context.getCommandContext().getHistoryManager().recordActivityEnd((ExecutionEntity) execution);
if (nbrOfExecutionsJoined==nbrOfExecutionsToJoin) {
execution.takeAll(outgoingTransitions, joinedExecutions);
}
}
}
省略了debug打印相关代码。第6行获取并行网关的所有“出线”。第7行把当前进入并行网关的那个execution的isActive属性设为false。第8行意义不明,如果读者明白的请告知。第10行寻找所有已经进入到并行网关的所有execution,其实现原理是判断当前进入的execution,如果是并行的execution,则通过其父execution寻找已经入并行网关的兄弟execution,如果非并行execution则返回自己。11行计算并行网关的“进线”,12行计算进入并行网关的execution数量。14行判断当进入网关的execution与“进线”的数量相等,则网关汇聚完成,执行15行takeAll离开网关。
接下来跟踪看下takeAll的执行,跟踪ExecutionEntity.java:
public class ExecutionEntity extends VariableScopeImpl implements ActivityExecution, ExecutionListenerExecution, Execution, PvmExecution,
ProcessInstance, InterpretableExecution, PersistentObject, HasRevision {
//......
public void takeAll(List<PvmTransition> transitions, List<ActivityExecution> recyclableExecutions) {
fireActivityCompletedEvent();
transitions = new ArrayList<PvmTransition>(transitions);
recyclableExecutions = (recyclableExecutions!=null ? new ArrayList<ActivityExecution>(recyclableExecutions) : new ArrayList<ActivityExecution>());
if (recyclableExecutions.size()>1) {
for (ActivityExecution recyclableExecution: recyclableExecutions) {
if (((ExecutionEntity)recyclableExecution).isScope()) {
throw new PvmException("joining scope executions is not allowed");
}
}
}
ExecutionEntity concurrentRoot = ((isConcurrent && !isScope) ? getParent() : this);
List<ExecutionEntity> concurrentActiveExecutions = new ArrayList<ExecutionEntity>();
List<ExecutionEntity> concurrentInActiveExecutions = new ArrayList<ExecutionEntity>();
for (ExecutionEntity execution: concurrentRoot.getExecutions()) {
if (execution.isActive()) {
concurrentActiveExecutions.add(execution);
} else {
concurrentInActiveExecutions.add(execution);
}
}
if ( (transitions.size()==1)
&& (concurrentActiveExecutions.isEmpty())
&& allExecutionsInSameActivity(concurrentInActiveExecutions)
) {
List<ExecutionEntity> recyclableExecutionImpls = (List) recyclableExecutions;
recyclableExecutions.remove(concurrentRoot);
for (ExecutionEntity prunedExecution: recyclableExecutionImpls) {
Context.getCommandContext().getHistoryManager().recordActivityEnd(prunedExecution);
prunedExecution.remove();
}
concurrentRoot.setActive(true);
concurrentRoot.setActivity(activity);
concurrentRoot.setConcurrent(false);
concurrentRoot.take(transitions.get(0), false);
} else {
List<OutgoingExecution> outgoingExecutions = new ArrayList<OutgoingExecution>();
recyclableExecutions.remove(concurrentRoot);
while (!transitions.isEmpty()) {
PvmTransition outgoingTransition = transitions.remove(0);
ExecutionEntity outgoingExecution = null;
if (recyclableExecutions.isEmpty()) {
outgoingExecution = concurrentRoot.createExecution();
} else {
outgoingExecution = (ExecutionEntity) recyclableExecutions.remove(0);
}
outgoingExecution.setActive(true);
outgoingExecution.setScope(false);
outgoingExecution.setConcurrent(true);
outgoingExecution.setTransitionBeingTaken((TransitionImpl) outgoingTransition);
outgoingExecutions.add(new OutgoingExecution(outgoingExecution, outgoingTransition, true));
}
for (ActivityExecution prunedExecution: recyclableExecutions) {
prunedExecution.end();
}
for (OutgoingExecution outgoingExecution: outgoingExecutions) {
outgoingExecution.take(false);
}
}
}
//......
}
11行为第二个传参,即汇聚到网关的execution。21行如果汇聚的execution是并行的,则获取其父execution,否则是其自身。32行判断当“出线”只有一条,且当前没有活动execution,并且这些不活动的execiution都处于一个activity中(即网关),则执行37-47行,否则执行49-74行。52-66行对每一个“出线”创建一个子execution,因此我们会看到并行网关有多少条“出线”,就有多少个对应的子execution。
上面的if分支可能有些读者没搞清楚情况,这里大概展示一下:
在第二个并行网关中汇聚了主流程的三条并行路由,而“出线”只有一条,这时候会走上面37-47行代码。除次之外,都会走49-74行。网关的“出线”大于1条,那条件判断自然毫无疑问,还有一种情况也要注意:
上面usertask2和usertask3汇聚的网关,就不会走37-47行。尽管“出线”是一条,但usertask1不会该网关中,因此usertask1对应的execution所处的Activity必然与usertask2和usertask3对应的execution所处的Activity不同,因此if((transitions.size()==1) && (concurrentActiveExecutions.isEmpty()) && allExecutionsInSameActivity(concurrentInActiveExecutions))的第二个条件或第三个条件必然不成立,即当usertask1未提交时,第二个条件不成立,当usertask1提交后,第三个条件必然不成立。这个判断有点复杂,读者需自行分析。