技术交流28群

服务热线

135-6963-3175

微信服务号

TakeOutgoingSequenceFlowsOperation出线源码解析 更新时间 2022-3-20 浏览2796次

节点是怎么流转出线的呢?

主要做的操作:
主要做了如下操作:
检查是否补偿节点,
 是:
    1.到这里停止执行,做清理操作并返回。
 否:
    1.离开当前活动时候,要删除任务相关的执行(例如活动边界事件);
       if. 当是一个父元素而非流程实例时候:则先销毁该元素范围内的,通过:Context.getAgenda().planDestroyScopeOperation(execution);
       else 若是一个任务节点:更新(ACT_HI_ACTINST表)实例历史数据并删除子执行的相关数据(但不删除定义了边界取消事件的节点)
            删除的子执行的数据有:
                            1.删除ACT_RU_IDENTITYLINK 
                            2.删除ACT_RU_VARIABLE 
                            3.删除ACT_GE_BYTEARRAY
                            4.删除ACT_RU_EXECUTION
    2.判断节点类型
        若是个节点:执行handleFlowNode操作:
                    a.记录结束时间等信息及监听器的触发
                    b.若是特别子流程:
                           1.如果有完成条件、判断条件是否满足
                           2.若出线大于0则:执行出线leaveFlowNode()
                                 出线为0则:执行删除执行相关数据操作(也就是可能是特殊子流程的最后一个节点了)
                           3.若1满足完成条件:
                                    判断:
                                    若特殊子流程不取消剩余实例:                                    
                                       a.判断是否结束特殊子流程: 查找是否还有其他的子执行,若是则不结束;                                    
                                       b.若结束则:Context.getAgenda().planEndExecutionOperation(execution.getParent()); 
                       否则:leaveFlowNode操作:
                                1.获取默认序列流(如果设置)
                                2.获取所有出线的表达式并计算(两种情况:未开启跳过则进行表达式计算;1条出线或配置必须跳过条件为true)
                                3.确定哪些序列流可用于离开。
                                4.步骤2结果数为0且需计算条件(则从该节点所有出线里找出默认出线);
                                5.没有发现出线。结束执行。(Context.getAgenda().planEndExecutionOperation(execution节点))
                                  否则:从集合获取第一条线设置active为true。
                                       并对所有出线创建子执行execution,并对所有子执行进行:Context.getAgenda().planContinueProcessOperation(outgoingExecution线)操作。   
        若是个线条:执行handleSequenceFlow操作。
                 1.更新结束信息(结束时间、花费时间、删除原因)
                 2.执行继续流程计划Context.getAgenda().planContinueProcessOperation(execution线);

貌似发现在TakeOutgoingSequenceFlowsOperation调用planContinueProcessOperation(execution线)参数都是seq线。

我们可以看TakeOutgoingSequenceFlowsOperation类的代码:

 @Override
 public void run() {
    //要出线的元素
    FlowElement currentFlowElement = getCurrentFlowElement(execution);
    // Compensation check 补偿检查
    if ((currentFlowElement instanceof Activity)
        && ( ((Activity) currentFlowElement)).isForCompensation()) {//任务节点的补偿检查
      /*
      如果当前流程元素是补偿的一部分,我们并不总是希望遵循离开活动的常规规则。
      更具体地说,如果没有传出序列流,我们只需在那里停止执行,而不是像我们通常做的那样在范围内找到传出序列流
       * If the current flow element is part of a compensation, we don't always
       * want to follow the regular rules of leaving an activity.
       * More specifically, if there are no outgoing sequenceflow, we simply must stop
       * the execution there and don't go up in the scopes as we usually do
       * to find the outgoing sequenceflow
       */
      cleanupCompensation();
      return;
    }
    //当离开当前活动时,我们需要删除任何相关的执行(例如活动边界事件)
    //When leaving the current activity, we need to delete any related execution (eg active boundary events)
    cleanupExecutions(currentFlowElement);
    if (currentFlowElement instanceof FlowNode) {//当前元素是个节点
      handleFlowNode((FlowNode) currentFlowElement);
    } else if (currentFlowElement instanceof SequenceFlow) {
      handleSequenceFlow();
    }
 }

主要做了如下操作:

  1. 检查是否补偿节点:

    是:的话则到这里停止执行,做清理操作并返回

    否:1、离开当前活动时候,要删除任务相关的执行(例如活动边界事件)

          2、若是个节点:执行handleFlowNode操作

               若是个线条:执行handleSequenceFlow操作。

我们首先来分析步骤2源码:cleanupExecutions(currentFlowElement);

protected void cleanupExecutions(FlowElement currentFlowElement) {
    if (execution.getParentId() != null && execution.isScope()) {
      // If the execution is a scope (and not a process instance), the scope must first be
      // destroyed before we can continue and follow the sequence flow
      //如果执行是一个范围(而不是流程实例),则必须首先销毁该范围,然后我们才能继续并遵循序列流
      Context.getAgenda().planDestroyScopeOperation(execution);
    } else if (currentFlowElement instanceof Activity) {//当是一个任务节点
      // If the current activity is an activity, we need to remove any currently active boundary events
      Activity activity = (Activity) currentFlowElement;
      if (CollectionUtil.isNotEmpty(activity.getBoundaryEvents())) {
        // Cancel events are not removed
        List<String> notToDeleteEvents = new ArrayList<String>();
        for (BoundaryEvent event : activity.getBoundaryEvents()) {
          if (CollectionUtil.isNotEmpty(event.getEventDefinitions()) &&
              event.getEventDefinitions().get(0) instanceof CancelEventDefinition) {
            notToDeleteEvents.add(event.getId());//边界取消事件定义
          }
        }
        // Delete all child executions
        Collection<ExecutionEntity> childExecutions = commandContext.getExecutionEntityManager().findChildExecutionsByParentExecutionId(execution.getId());
        for (ExecutionEntity childExecution : childExecutions) {
          if (childExecution.getCurrentFlowElement() == null || !notToDeleteEvents.contains(childExecution.getCurrentFlowElement().getId())) {
            commandContext.getExecutionEntityManager().deleteExecutionAndRelatedData(childExecution, null, false);
          }
        }
      }
    }
  }

可以看到:

if. 当是一个父元素而非流程实例时候:则先销毁该元素范围内的,通过:Context.getAgenda().planDestroyScopeOperation(execution);

else 若是一个任务节点更新(ACT_HI_ACTINST表)实例历史数据并删除子执行的相关数据(但不删除定义了边界取消事件的节点)

       删除的子执行的数据有:

            1.删除ACT_RU_IDENTITYLINK 

            2.删除ACT_RU_VARIABLE 

            3.删除ACT_GE_BYTEARRAY

            4.删除ACT_RU_EXECUTION

接下来分析步骤3:

handleFlowNode((FlowNode) currentFlowElement);

protected void handleFlowNode(FlowNode flowNode) {
    handleActivityEnd(flowNode);//记录结束时间等信息及监听器的触发
    if (flowNode.getParentContainer() != null
        && flowNode.getParentContainer() instanceof AdhocSubProcess) {//特别子流程
      handleAdhocSubProcess(flowNode);
    } else {
      leaveFlowNode(flowNode);
    }
  }

代码主要操作:

1、记录结束时间等信息及监听器的触发

2、若是特别子流程则处理

        否则:离开节点

特别子流程处理:

protected void handleAdhocSubProcess(FlowNode flowNode) {
    boolean completeAdhocSubProcess = false;
    AdhocSubProcess adhocSubProcess = (AdhocSubProcess) flowNode.getParentContainer();
    if (adhocSubProcess.getCompletionCondition() != null) {
      Expression expression = Context.getProcessEngineConfiguration().getExpressionManager().createExpression(adhocSubProcess.getCompletionCondition());
      Condition condition = new UelExpressionCondition(expression);
      if (condition.evaluate(adhocSubProcess.getId(), execution)) {//条件判断
        completeAdhocSubProcess = true;
      }
    }
    if (flowNode.getOutgoingFlows().size() > 0) {
      leaveFlowNode(flowNode);
    } else {
      commandContext.getExecutionEntityManager().deleteExecutionAndRelatedData(execution, null, false);
    }
    if (completeAdhocSubProcess) {//完成
      boolean endAdhocSubProcess = true;
      if (adhocSubProcess.isCancelRemainingInstances() == false) {//不取消剩余实例
        List<ExecutionEntity> childExecutions = commandContext.getExecutionEntityManager().findChildExecutionsByParentExecutionId(execution.getParentId());
        for (ExecutionEntity executionEntity : childExecutions) {
          if (executionEntity.getId().equals(execution.getId()) == false) {
            endAdhocSubProcess = false;
            break;
          }
        }
      }
      if (endAdhocSubProcess) {//结束特殊子流程
        Context.getAgenda().planEndExecutionOperation(execution.getParent());
      }
    }
}

主要操作

  1. 如果有完成条件、判断条件是否满足

  2. 若出线大于0则执行出线leaveFlowNode()

    出线为0则:执行删除执行相关数据操作(也就是可能是特殊子流程的最后一个节点了)

  3. 若满足完成条件:

               判断:

          1. 若特殊子流程不取消剩余实例:

               判断是否结束特殊子流程: 查找是否还有其他的子执行,若是则不结束;

          2. 若结束则:Context.getAgenda().planEndExecutionOperation(execution.getParent());

接下来分析leaveFlowNode(flowNode):

protected void leaveFlowNode(FlowNode flowNode) {
    logger.debug("Leaving flow node {} with id '{}' by following it's {} outgoing sequenceflow",
        flowNode.getClass(), flowNode.getId(), flowNode.getOutgoingFlows().size());
    // Get default sequence flow (if set)
    //获取默认序列流(如果设置)
    String defaultSequenceFlowId = null;
    if (flowNode instanceof Activity) {
      defaultSequenceFlowId = ((Activity) flowNode).getDefaultFlow();
    } else if (flowNode instanceof Gateway) {
      defaultSequenceFlowId = ((Gateway) flowNode).getDefaultFlow();
    }
    // Determine which sequence flows can be used for leaving
    //确定哪些序列流可用于离开
    List<SequenceFlow> outgoingSequenceFlows = new ArrayList<SequenceFlow>();
    for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {//获取所有出线的表达式并计算
      //获取跳过表达式
      String skipExpressionString = sequenceFlow.getSkipExpression();
      //_ACTIVITI_SKIP_EXPRESSION_ENABLED全局变量是否开启跳过表达式
      if (!SkipExpressionUtil.isSkipExpressionEnabled(execution, skipExpressionString)) {//未开启跳过表达式则计算
          //忽略计算条件(false)或者(条件表达式计算为true且(默认出现为null或非默认出线))
        if (!evaluateConditions
            || (evaluateConditions && ConditionUtil.hasTrueCondition(sequenceFlow, execution) && (defaultSequenceFlowId == null || !defaultSequenceFlowId.equals(sequenceFlow.getId())))) {
          outgoingSequenceFlows.add(sequenceFlow);
        }
      } else if (flowNode.getOutgoingFlows().size() == 1 ||  //1条出线或配置必须跳过条件为true
              SkipExpressionUtil.shouldSkipFlowElement(commandContext, execution, skipExpressionString)) {
        // The 'skip' for a sequence flow means that we skip the condition, not the sequence flow.
        //序列流的“跳过”意味着我们跳过条件,而不是序列流。
        //出线为1或者计算应该跳过流元素
        outgoingSequenceFlows.add(sequenceFlow);
      }
    }
    // Check if there is a default sequence flow 检查是否有默认的序列流,默认的加入出线集合
    //出线为0且需计算条件(找出默认出线)
    if (outgoingSequenceFlows.size() == 0 && evaluateConditions) { // The elements that set this to false also have no support for default sequence flow
      if (defaultSequenceFlowId != null) {
        for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
          if (defaultSequenceFlowId.equals(sequenceFlow.getId())) {
            outgoingSequenceFlows.add(sequenceFlow);
            break;
          }
        }
      }
    }
    // No outgoing found. Ending the execution 没有发现出线。结束执行
    if (outgoingSequenceFlows.size() == 0) {
      if (flowNode.getOutgoingFlows() == null || flowNode.getOutgoingFlows().size() == 0) {
        logger.debug("No outgoing sequence flow found for flow node '{}'.", flowNode.getId());
        Context.getAgenda().planEndExecutionOperation(execution);
      } else {
        throw new ActivitiException("No outgoing sequence flow of element '" + flowNode.getId() + "' could be selected for continuing the process");
      }
    } else {
      // Leave, and reuse the incoming sequence flow, make executions for all the others (if applicable)
      ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
      List<ExecutionEntity> outgoingExecutions = new ArrayList<ExecutionEntity>(flowNode.getOutgoingFlows().size());
      //获取第一条线
      SequenceFlow sequenceFlow = outgoingSequenceFlows.get(0);
      // Reuse existing one
      execution.setCurrentFlowElement(sequenceFlow);
      execution.setActive(true);
      outgoingExecutions.add((ExecutionEntity) execution);
      // Executions for all the other one
      if (outgoingSequenceFlows.size() > 1) {
        for (int i = 1; i < outgoingSequenceFlows.size(); i++) {
          ExecutionEntity parent = execution.getParentId() != null ? execution.getParent() : execution;
          //大于一个出线,则为所有的出线入库(并行网关等...)
          ExecutionEntity outgoingExecutionEntity = commandContext.getExecutionEntityManager().createChildExecution(parent);
          SequenceFlow outgoingSequenceFlow = outgoingSequenceFlows.get(i);
          outgoingExecutionEntity.setCurrentFlowElement(outgoingSequenceFlow);
          executionEntityManager.insert(outgoingExecutionEntity);
          outgoingExecutions.add(outgoingExecutionEntity);
        }
      }
      // Leave (only done when all executions have been made, since some queries depend on this) 离开(仅在所有执行完成后才完成,因为某些查询依赖于此)
      for (ExecutionEntity outgoingExecution : outgoingExecutions) {
        Context.getAgenda().planContinueProcessOperation(outgoingExecution);
      }
    }
  }

分析代码,主要执行的操作:

  1. 获取默认序列流(如果设置)

  2. 获取所有出线的表达式并计算(两种情况:未开启跳过则进行表达式计算;1条出线或配置必须跳过条件为true)

    确定哪些序列流可用于离开。

  3. 步骤2结果数为0且需计算条件(则从该节点所有出线里找出默认出线);

  4. 没有发现出线。结束执行。(Context.getAgenda().planEndExecutionOperation(execution节点)

    否则:从集合获取第一条线设置active为true。

             并对所有出线创建子执行execution,并对所有子执行进行: Context.getAgenda().planContinueProcessOperation(outgoingExecution线)操作。

分析步骤3handleSequenceFlow()方法:

protected void handleSequenceFlow() {
    commandContext.getHistoryManager().recordActivityEnd(execution, null);
    Context.getAgenda().planContinueProcessOperation(execution);
}

主要进行操作:

1.更新结束信息(结束时间、花费时间、删除原因)

2.执行继续流程计划Context.getAgenda().planContinueProcessOperation(execution);