activiti学习(二十六)——流程虚拟机源码分析(五)——并行网关的行为

本文分析一下并行网关的行为。并行网关本身的控制还是比较简单的,复杂的主要在于出口,直接上代码,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提交后,第三个条件必然不成立。这个判断有点复杂,读者需自行分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值