技术交流28群

服务热线

135-6963-3175

微信服务号

EndExecutionOperation源码解析 更新时间 2022-3-23 浏览2088次

流程是怎么结束执行的呢?

此操作结束执行并遵循典型的 BPMN 规则以继续该流程。此操作通常不是通过 {@link ActivityBehavior} 行为安排的,

而是从另一个操作安排的。当条件使得流程无法通过常规方式继续并且需要进行执行清理时,就会发生这种情况,这可能会开辟继续流程实例的新方式。

1.节点出线为0时候

2.结束特殊子流程时候

3.清理补偿时候,实例类型结束执行

概要:

若是流程实例级别:
1.找父实例
  存在父执行:在销毁结束的子流程实例(callActivity)之前保存变量。(通过调用父执行当前元素的行为类的completing方法)
2.获取存活的子执行数量
  0:通过流程实例id删除实例相关数据(所有);
3.流程存在执行监听器则执行结束"end"执行监听器;
4.存在父执行,父执行实例的子流程实例设置为null,并通过调用父执行元素活动行为类的completed用于离开;

否:
1.如果执行是父但非流程实例:则必须首先删除所有子执行。
2.删除执行实例相关数据
3.多实例子流程中结束执行时:处理多实例子流程
4.如果没有更多活动的子执行,则流程可以继续(例如嵌入式子流程仍有活动元素,我们无法继续)
  a.在结束子流程的情况下:
    是补偿:那么我们不需要做任何事情,可以结束它(planEndExecutionOperation(parentExecution))
    非补偿:处理子流程结束:handleSubProcessEnd()
  b.非子流程:
    处理规则执行end:handleRegularExecutionEnd()
  c.若ab执行后executionToContinue:
           不为空:(如果执行不是流程实例根执行,则仅继续传出序列流(否则流程实例已完成))
                流程实例类型:(handleProcessInstanceExecution(该方法上面已分析过))
                否则:planTakeOutgoingSequenceFlowsOperation()

我们可以看下EndExecutionOperationd类的核心代码:

@Override
public void run() {
    if (execution.isProcessInstanceType()) {//流程实例级别
      1.找父实例执行
       存在父执行则:在销毁结束的子流程实例(调用活动)之前复制变量(用于保存内嵌子流程的变量到库和执行实例execution)
      2.获取存活的子执行数量
        注意这里使用流程实例执行来获取流程元素(删除实例相关数据(所有))
      3.执行结束"end"监听器。(当节点的执行监听器集合不为空)
      4.存在父执行:"离开操作"(AbstractBpmnActivityBehavior.leave())
      handleProcessInstanceExecution(execution);
    } else {
      1.如果执行是父元素但非流程实例,则必须首先删除所有子执行。
      2.删除当前执行
      3. 在多实例子流程中结束执行时:
          处理多实例子流程
      4.如果没有更多活动的子执行,则流程可以继续(例如嵌入式子流程仍有活动元素,我们无法继续)
        若当前元素有子流程:
                补偿:则planEndExecutionOperation(parent)
                否则:
      handleRegularExecution();
    }
}

分析代码:

若是流程实例级别:执行handleProcessInstanceExecution(execution);方法

                  否则:执行handleRegularExecution();

我们首先来分析流程实例处理方法handleProcessInstanceExecution:

protected void handleProcessInstanceExecution(ExecutionEntity processInstanceExecution) {
    ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
    String processInstanceId = processInstanceExecution.getId(); // No parent execution == process instance id
    logger.debug("No parent execution found. Verifying if process instance {} can be stopped.", processInstanceId);
    ExecutionEntity superExecution = processInstanceExecution.getSuperExecution();//找父实例
    SubProcessActivityBehavior subProcessActivityBehavior = null;
    //在销毁结束的子流程实例(调用活动)之前复制变量
    // copy variables before destroying the ended sub process instance (call activity)
    if (superExecution != null) {//存在父执行
      FlowNode superExecutionElement = (FlowNode) superExecution.getCurrentFlowElement();
      subProcessActivityBehavior = (SubProcessActivityBehavior) superExecutionElement.getBehavior();
      try {
        subProcessActivityBehavior.completing(superExecution, processInstanceExecution);//用于保存内嵌子流程的变量到库和执行实例execution
      } catch (RuntimeException e) {
        logger.error("Error while completing sub process of execution {}", processInstanceExecution, e);
        throw e;
      } catch (Exception e) {
        logger.error("Error while completing sub process of execution {}", processInstanceExecution, e);
        throw new ActivitiException("Error while completing sub process of execution " + processInstanceExecution, e);
      }
    }
    //获取存活的子执行数量
    int activeExecutions = getNumberOfActiveChildExecutionsForProcessInstance(executionEntityManager, processInstanceId);
    if (activeExecutions == 0) {
      logger.debug("No active executions found. Ending process instance {} ", processInstanceId);
      //注意这里使用流程实例执行来获取流程元素(删除实例相关数据(所有))
   // note the use of execution here vs processinstance execution for getting the flowelement
      executionEntityManager.deleteProcessInstanceExecutionEntity(processInstanceId,
          execution.getCurrentFlowElement() != null ? execution.getCurrentFlowElement().getId() : null, null, false, false);
    } else {
      logger.debug("Active executions found. Process instance {} will not be ended.", processInstanceId);
    }
    Process process = ProcessDefinitionUtil.getProcess(processInstanceExecution.getProcessDefinitionId());
    // Execute execution listeners for process end. 执行结束监听器。
    if (CollectionUtil.isNotEmpty(process.getExecutionListeners())) {
      executeExecutionListeners(process, processInstanceExecution, ExecutionListener.EVENTNAME_END);//"end"
    }
    // and trigger execution afterwards if doing a call activity
    if (superExecution != null) {
      superExecution.setSubProcessInstance(null);
      try {
        subProcessActivityBehavior.completed(superExecution);//用于离开
      } catch (RuntimeException e) {
        logger.error("Error while completing sub process of execution {}", processInstanceExecution, e);
        throw e;
      } catch (Exception e) {
        logger.error("Error while completing sub process of execution {}", processInstanceExecution, e);
        throw new ActivitiException("Error while completing sub process of execution " + processInstanceExecution, e);
      }
    }
}

分析代码,主要操作:

1.找父实例

  存在父执行:在销毁结束的子流程实例(调用活动)之前保存变量。(通过调用父执行当前元素的行为类的completing方法

2.获取存活的子执行数量

  0:删除实例相关数据(所有),通过流程实例id;

3.流程存在执行监听器则执行结束"end"执行监听器;

4.存在父执行,父执行实例的子流程实例设置为null,并通过调用父执行元素活动行为类的completed用于离开

可以看下CallActivityBehavior行为类的completing方法:

public void completing(DelegateExecution execution, DelegateExecution subProcessInstance) throws Exception {
    // only data. no control flow available on this execution.
    ExpressionManager expressionManager = Context.getProcessEngineConfiguration().getExpressionManager();
    // copy process variables
    ExecutionEntity executionEntity = (ExecutionEntity) execution;
    CallActivity callActivity = (CallActivity) executionEntity.getCurrentFlowElement();//活动调用
    for (IOParameter ioParameter : callActivity.getOutParameters()) {//出参数
      Object value = null;
      if (StringUtils.isNotEmpty(ioParameter.getSourceExpression())) {//参数表达式计算值
        Expression expression = expressionManager.createExpression(ioParameter.getSourceExpression().trim());
        value = expression.getValue(subProcessInstance);
      } else {
        value = subProcessInstance.getVariable(ioParameter.getSource());
      }
      execution.setVariable(ioParameter.getTarget(), value);//设置变量
    }
}

发现该方法会获取活动的所有出参数并参与表达式计算,进行变量入库。

而CallActivityBehavior的completed方法:

public void completed(DelegateExecution execution) throws Exception {
    // only control flow. no sub process instance data available 只控制流。没有可用的子流程实例数据
    leave(execution);
}

用于离开节点。

最终调用了父类AbstractBpmnActivityBehavior的leave方法:

public void leave(DelegateExecution execution) {
    FlowElement currentFlowElement = execution.getCurrentFlowElement();
    //查找该节点的边界事件
    Collection<BoundaryEvent> boundaryEvents = findBoundaryEventsForFlowNode(execution.getProcessDefinitionId(), currentFlowElement);
    if (CollectionUtil.isNotEmpty(boundaryEvents)) {
      //执行边界事件
      executeCompensateBoundaryEvents(boundaryEvents, execution);
    }
    if (!hasLoopCharacteristics()) {//没有多实例
      super.leave(execution);
    } else if (hasMultiInstanceCharacteristics()) {//执行多实例行为
      multiInstanceActivityBehavior.leave(execution);
    }
  }

后面调用了FlowNodeActivityBehavior的leave():

public void leave(DelegateExecution execution) {
    //执行出线计算-执行默认传出行为
    bpmnActivityBehavior.performDefaultOutgoingBehavior((ExecutionEntity) execution);
}
----最终通过Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution, true);进行离开

接下来我们分析handleRegularExecution():

protected void handleRegularExecution() {
    ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
    // There will be a parent execution (or else we would be in the process instance handling method)
    ExecutionEntity parentExecution = executionEntityManager.findById(execution.getParentId());
    // If the execution is a scope, all the child executions must be deleted first.
    if (execution.isScope()) {//如果执行是父但非流程实例,则必须首先删除所有子执行。
      executionEntityManager.deleteChildExecutions(execution, null, false);
    }
    // Delete current execution
    logger.debug("Ending execution {}", execution.getId());
    executionEntityManager.deleteExecutionAndRelatedData(execution, null, false);
    logger.debug("Parent execution found. Continuing process using execution {}", parentExecution.getId());
    // 需要特别注意: 在多实例子流程中结束执行时;
    // When ending an execution in a multi instance subprocess , special care is needed
    if (isEndEventInMultiInstanceSubprocess(execution)) {
        handleMultiInstanceSubProcess(executionEntityManager, parentExecution);//处理多实例子流程
        return;
    }
    SubProcess subProcess = execution.getCurrentFlowElement().getSubProcess();
    // 如果没有更多活动的子执行,则流程可以继续(例如嵌入式子流程仍有活动元素,我们无法继续)
    // If there are no more active child executions, the process can be continued
    // If not (eg an embedded subprocess still has active elements, we cannot continue)
    if (getNumberOfActiveChildExecutionsForExecution(executionEntityManager, parentExecution.getId()) == 0
        || isAllEventScopeExecutions(executionEntityManager, parentExecution)) {
      ExecutionEntity executionToContinue = null;
      if (subProcess != null) {
        // 在结束子流程的情况下:进入范围并通过父范围继续,除非它是补偿,那么我们不需要做任何事情,可以结束它
        // In case of ending a subprocess: go up in the scopes and continue via the parent scope
        // unless its a compensation, then we don't need to do anything and can just end it
        if (subProcess.isForCompensation()) {
          Context.getAgenda().planEndExecutionOperation(parentExecution);
        } else {
          //处理子流程结束
          executionToContinue = handleSubProcessEnd(executionEntityManager, parentExecution, subProcess);
        }
      } else {
        // In the 'regular' case (not being in a subprocess), we use the parent execution to
        // continue process instance execution
        // 处理规则执行end
        executionToContinue = handleRegularExecutionEnd(executionEntityManager, parentExecution);
      }
      if (executionToContinue != null) {
        // 如果执行不是流程实例根执行,则仅继续传出序列流(否则流程实例已完成)
        // only continue with outgoing sequence flows if the execution is
        // not the process instance root execution (otherwise the process instance is finished)
        if (executionToContinue.isProcessInstanceType()) {//流程实例类型
          handleProcessInstanceExecution(executionToContinue);
        } else {
          Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(executionToContinue, true);
        }
      }
    }
  }

分析代码,做了操作:

  1. 如果执行是父但非流程实例,则必须首先删除所有子执行。

  2. 删除执行实例相关数据

  3. 多实例子流程中结束执行时:处理多实例子流程

  4. 如果没有更多活动的子执行,则流程可以继续(例如嵌入式子流程仍有活动元素,我们无法继续)

    1. 在结束子流程的情况下:

      1. 是补偿:那么我们不需要做任何事情,可以结束它(planEndExecutionOperation(parentExecution))

      2. 非补偿:处理子流程结束:handleSubProcessEnd()

    2. 非子流程:

      1. 处理规则执行end:handleRegularExecutionEnd()

        c.若ab执行后executionToContinue:

                不为空:(如果执行不是流程实例根执行,则仅继续传出序列流(否则流程实例已完成))

                        流程实例类型:(handleProcessInstanceExecution(该方法上面已分析过))

                        否则:planTakeOutgoingSequenceFlowsOperation()