02 流程流转

发布于:2025-08-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

审批流程图

        如下图,在此流程图中,存在两个UserTask节点,第一个节点是主管审批,第二个节点是产品经理审批,两个节点中间有一个排他网关,此网关用来对主管审批的结果进行判断,如果主管审批通过,则流程走到产品经理审批节点,如果主管审批拒绝,则流程走到结束节点。

        主管审批节点通过UEL表达式${assignManager}动态赋值,产品经理审批节点通过UEL表达式${assignProductLineManager}动态赋值,网关节点通过UEL表达式${isPass}动态赋值。

流程流转

        上文 《01 启动流程实例》 讲到在完成流程实例的启动后,流程将通过commandContext.getAgenda().planContinueProcessOperation(execution)流转到下一个节点。本文将以此代码为入口,研究流程如何流转到下一个节点。

        上面的代码中,getAgent 方法返回来一个 ActivitiEngineAgenda 接口,此接口的实现类是DefaultActivitiEngineAgenda,它的内部成员属性如下,operations 在这里充当 FIFO 队列,用来存储将要执行的 AbstractOperation (本质上是一个 Runnable 接口)操作,而 CommandContext 则是命令上下文。

public class DefaultActivitiEngineAgenda implements ActivitiEngineAgenda {

    private static final Logger logger = LoggerFactory.getLogger(DefaultActivitiEngineAgenda.class);

    protected LinkedList<Runnable> operations = new LinkedList<Runnable>();
    protected CommandContext commandContext;
    
    public DefaultActivitiEngineAgenda(CommandContext commandContext) {
      this.commandContext = commandContext;
    }
    // 省略部分代码
}

ContinueProcessOperation 操作(第一次)

构造 ContinueProcessOperation

        planContinueProcessOperation(execution在 DefaultActivitiEngineAgenda 中的实现如下,把传入的 execution commandContext 构造一个 ContinueProcessOperation 实例,并放入了 operations 队列中,

@Override
public void planContinueProcessOperation(ExecutionEntity execution) {
    planOperation(new ContinueProcessOperation(commandContext, execution));
}

@Override
public void planOperation(Runnable operation) {
    // 将 operation 任务放到 operations 队列中,等待定时任务从队列中取出任务并执行
    operations.add(operation);

    if (operation instanceof AbstractOperation) {
        ExecutionEntity execution = ((AbstractOperation) operation).getExecution();
        if (execution != null) {
            // 这里添加的内容,在 org/activiti/engine/impl/interceptor/CommandInvoker的execute(CommandConfig, Command<T>) 
            // 中有使用,目的是告诉 CommandInvoker 有待执行的 AbstractOperation
            commandContext.addInvolvedExecution(execution);
        }
    }

    logger.debug("Operation {} added to agenda", operation.getClass());
}

        ContinueProcessOperation 类定义如下:

public abstract class AbstractOperation implements Runnable {
    // 省略部分代码
}


public class ContinueProcessOperation extends AbstractOperation {
    // 省略部分代码
}

执行 ContinueProcessOperation

        由异步任务执行器 org/activiti/engine/impl/asyncexecutor/DefaultAsyncJobExecutor 中的 AcquireAsyncJobsDueRunnable 调用 DefaultActivitiEngineAgenda getNextOperation 来取出 operations 队列中的 AbstractOperation 任务,然后由 CommandInvoker 来执行(异步任务执行器 DefaultAsyncJobExecutor 是在我们调用 ProcessEngines.getDefaultProcessEngine() 创建 ProcessEngine 阶段完成的初始化)。

        CommandInvoker 中执行 AbstractOperation 任务的代码是下面这一段

protected void executeOperations(final CommandContext commandContext) {
  // 任务不是空的
  while (!commandContext.getAgenda().isEmpty()) {
    // 取出任务
    Runnable runnable = commandContext.getAgenda().getNextOperation();
    // 执行任务
    executeOperation(runnable);
  }
}

public void executeOperation(Runnable runnable) {
  // ContinueProcessOperation 继承 AbstractOperation,所以这个if条件的值是true,进入此if内部逻辑
  // 除了 ContinueProcessOperation 外, 其它继承 AbstractOperation 的Operation类都能进入这个if逻辑
  if (runnable instanceof AbstractOperation) {
    AbstractOperation operation = (AbstractOperation) runnable;

    // Execute the operation if the operation has no execution (i.e. it's an operation not working on a process instance)
    // or the operation has an execution and it is not ended
    if (operation.getExecution() == null || !operation.getExecution().isEnded()) {

      if (logger.isDebugEnabled()) {
        logger.debug("Executing operation {} ", operation.getClass());
      }
      // 直接调用 ContinueProcessOperation(Runnable)的run方法,
      // 会不会开启异步线程?不会,直接调用run方法,就是调用一个普通的方法
      runnable.run();

    }

  } else {
    // 直接调用 Runnable 的run方法,会不会开启异步线程?不会,直接调用run方法,就是调用一个普通的方法
    runnable.run();
  }
}

        执行 ContinueProcessOperation run() 方法后,来到了 ContinueProcessOperation

public class ContinueProcessOperation extends AbstractOperation {

    // 省略部分代码
    /**
     * 当 ContinueProcessOperation 操作被执行时,以 run 方法作为入口
     */
    @Override
    public void run() {
        // 第一次执行这个逻辑,取出来的 currentFlowElement 是一个 StartEvent,StartEvent 是 FlowNode 的子类
        FlowElement currentFlowElement = getCurrentFlowElement(execution);
        if (currentFlowElement instanceof FlowNode) {
            // 继续执行 FlowNode 类型的类,StartEvent会走这个方法
            continueThroughFlowNode((FlowNode) currentFlowElement);
        } else if (currentFlowElement instanceof SequenceFlow) {
            // 继续执行 SequenceFlow 类型的类
            continueThroughSequenceFlow((SequenceFlow) currentFlowElement);
        } else {
            throw new ActivitiException("Programmatic error: no current flow element found or invalid type: " + currentFlowElement + ". Halting.");
        }
    }

    protected void continueThroughFlowNode(FlowNode flowNode) {

        // Check if it's the initial flow element. If so, we must fire the execution listeners for the process too
        if (flowNode.getIncomingFlows() != null
                && flowNode.getIncomingFlows().size() == 0
                && flowNode.getSubProcess() == null) {
            executeProcessStartExecutionListeners();
        }

        // For a subprocess, a new child execution is created that will visit the steps of the subprocess
        // The original execution that arrived here will wait until the subprocess is finished
        // and will then be used to continue the process instance.
        if (flowNode instanceof SubProcess) {
            createChildExecutionForSubProcess((SubProcess) flowNode);
        }

        if (flowNode instanceof Activity && ((Activity) flowNode).hasMultiInstanceLoopCharacteristics()) {
            // the multi instance execution will look at async
            executeMultiInstanceSynchronous(flowNode);
        } else if (forceSynchronousOperation || !flowNode.isAsynchronous()) {
            // 同步执行,StartEvent走的是这里
            executeSynchronous(flowNode);
        } else {
            // 异步执行
            executeAsynchronous(flowNode);
        }
    }

    /**
     * 同步执行
     * @param flowNode
     */
    protected void executeSynchronous(FlowNode flowNode) {
        // 调用HistoryManager记录流程活动开始了,这里并不是单单指StartEvent活动,而是所有活动
        commandContext.getHistoryManager().recordActivityStart(execution);

        // Execution listener: event 'start'
        // 执行 StartEvent 上的监听器,发布 Start 的 Event 事件
        if (CollectionUtil.isNotEmpty(flowNode.getExecutionListeners())) {
            executeExecutionListeners(flowNode, ExecutionListener.EVENTNAME_START);
        }

        // Execute any boundary events, sub process boundary events will be executed from the activity behavior
        if (!inCompensation && flowNode instanceof Activity) { // Only activities can have boundary events
            // 获取节点上的边界事件,如果有,就执行
            List<BoundaryEvent> boundaryEvents = ((Activity) flowNode).getBoundaryEvents();
            if (CollectionUtil.isNotEmpty(boundaryEvents)) {
                executeBoundaryEvents(boundaryEvents, execution);
            }
        }

        // Execute actual behavior
        // 取出节点上的行为
        ActivityBehavior activityBehavior = (ActivityBehavior) flowNode.getBehavior();
        // 当 activityBehavior 不为空,走此方法,此方法后续也会调用 planTakeOutgoingSequenceFlowsOperation
        // activityBehavior 表示一个节点上拥有的行为
        // StartEvent 节点的行为是 NoneStartEventActivityBehavior,没有做其它业务,仅仅是过度
        // UserTask   节点的行为是 UserTaskActivityBehavior,这个行为会把任务写入到数据库后,等待用户完成任务,流程才会继续走下去
        if (activityBehavior != null) {
            // 执行节点上的行为,StartEvent后走的是这里,
            executeActivityBehavior(activityBehavior, flowNode);
        } else {
            logger.debug("No activityBehavior on activity '{}' with execution {}", flowNode.getId(), execution.getId());
            // StartEvent后不走这里,计划执行 TakeOutgoingSequenceFlows 操作,这个操作是一个连线行为,第一步先找出当前节点的出口,第二步从出口走到下一个节点。
            Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution, true);
        }
    }

    /**
     * 执行节点上的行为
     * @param activityBehavior
     * @param flowNode
     */
    protected void executeActivityBehavior(ActivityBehavior activityBehavior,
                                           FlowNode flowNode) {
        logger.debug("Executing activityBehavior {} on activity '{}' with execution {}",
                     activityBehavior.getClass(),
                     flowNode.getId(),
                     execution.getId());

        if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
            Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
                    ActivitiEventBuilder.createActivityEvent(ActivitiEventType.ACTIVITY_STARTED,
                                                             flowNode.getId(),
                                                             flowNode.getName(),
                                                             execution.getId(),
                                                             execution.getProcessInstanceId(),
                                                             execution.getProcessDefinitionId(),
                                                             flowNode));
        }

        try {
            // 这方法里面后续会执行 planTakeOutgoingSequenceFlowsOperation
            // 执行 StartEvent 的 NoneStartEventActivityBehavior 行为
            activityBehavior.execute(execution);
        } catch (RuntimeException e) {
            if (LogMDC.isMDCEnabled()) {
                LogMDC.putMDCExecution(execution);
            }
            throw e;
        }
    }
}

执行 NoneStartEventActivityBehavior

        因为 NoneStartEventActivityBehavior 是空实现,但它继承自 FlowNodeActivityBehavior ,拥有了父类的能力,所以 activityBehavior.execute(execution) 实际执行的是父类FlowNodeActivityBehavior execute(DelegateExecution) 方法。

public class NoneStartEventActivityBehavior extends FlowNodeActivityBehavior {

  private static final long serialVersionUID = 1L;

  // Nothing to see here.
  // The default behaviour of the BpmnActivity is exactly what
  // a none start event should be doing.

}

        在 execute(DelegateExecution) 方法中调用了 leave(execution) 方法,详情见代码


public abstract class FlowNodeActivityBehavior implements TriggerableActivityBehavior {

  private static final long serialVersionUID = 1L;

  protected BpmnActivityBehavior bpmnActivityBehavior = new BpmnActivityBehavior();

  /**
   * Default behaviour: just leave the activity with no extra functionality.
   * NoneStartEventActivityBehavior 自己没有实现 execute 方法,所以会调用父类
   * FlowNodeActivityBehavior 的 execute 方法
   */
  public void execute(DelegateExecution execution) {
    leave(execution);
  }

  /**
   * Default way of leaving a BPMN 2.0 activity: evaluate the conditions on the outgoing sequence flow and take those that evaluate to true.
   * 离开 BPMN 2.0 activity的默认方式:评估 Outgoing sequence 流上的条件,并选取那些评估为 true 的条件
   */
  public void leave(DelegateExecution execution) {
    // 走到 bpmnActivityBehavior 中的 performDefaultOutgoingBehavior 方法
    bpmnActivityBehavior.performDefaultOutgoingBehavior((ExecutionEntity) execution);
  }
}

        BpmnActivityBehavior performDefaultOutgoingBehavior 内部调用 Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(ExecutionEntity, boolean) 方法,这里的 Context.getAgenda() 获取到的 Agenda 和上面的 Agenda 是同一个,取到 Agenda后,调用了它的 planTakeOutgoingSequenceFlowsOperation(ExecutionEntity, boolean) 方法,此方法将产生连线行为,将 StartEvent 根据 Process 流程模型的定义连接到下一个节点。

public class BpmnActivityBehavior implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * Performs the default outgoing BPMN 2.0 behavior, which is having parallel paths of executions for the outgoing sequence flow.
     * <p>
     * More precisely: every sequence flow that has a condition which evaluates to true (or which doesn't have a condition), is selected for continuation of the process instance. If multiple sequencer
     * flow are selected, multiple, parallel paths of executions are created.
     */
    public void performDefaultOutgoingBehavior(ExecutionEntity activityExecution) {
        performOutgoingBehavior(activityExecution,
                                true,
                                false);
    }
    
    /**
     * Actual implementation of leaving an activity.
     * @param execution The current execution context
     * @param checkConditions Whether or not to check conditions before determining whether or not to take a transition.
     * @param throwExceptionIfExecutionStuck If true, an {@link ActivitiException} will be thrown in case no transition could be found to leave the activity.
     * 最后在这个方法里调用了 planTakeOutgoingSequenceFlowsOperation 方法,用于走出当前就节点,走到下一个节点
     */
    protected void performOutgoingBehavior(ExecutionEntity execution,
                                           boolean checkConditions,
                                           boolean throwExceptionIfExecutionStuck) {
        Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution,
                                                                   true);
    }
}

TakeOutgoingSequenceFlowsOperation 操作

构造 TakeOutgoingSequenceFlowsOperation

        DefaultActivitiEngineAgenda planTakeOutgoingSequenceFlowsOperation 方法如下,将 ExecutionEntity 封装成 TakeOutgoingSequenceFlowsOperation,再放入 operations 队列中。

public class DefaultActivitiEngineAgenda implements ActivitiEngineAgenda {
    @Override
    public void planTakeOutgoingSequenceFlowsOperation(ExecutionEntity execution, boolean evaluateConditions) {
        planOperation(new TakeOutgoingSequenceFlowsOperation(commandContext, execution, evaluateConditions));
    }
}

执行 TakeOutgoingSequenceFlowsOperation

        TakeOutgoingSequenceFlowsOperation 也和 ContinueProcessOperation 一样是 AbstractionOperation 的子类,同样也是由定时任务通过 CommandInvoker 来调用 TakeOutgoingSequenceFlowsOperation 中的 run() 方法。

public class TakeOutgoingSequenceFlowsOperation extends AbstractOperation {
    
    // 省略部分代码

    @Override
    public void run() {
        FlowElement currentFlowElement = getCurrentFlowElement(execution);
        // Compensation check
        if ((currentFlowElement instanceof Activity)
                && (((Activity) currentFlowElement)).isForCompensation()) {
            cleanupCompensation();
            return;
        }

        // When leaving the current activity, we need to delete any related execution (eg active boundary events)
        // 清除当前节点的一些附属信息
        cleanupExecutions(currentFlowElement);
        // 当前 currentFlowElement 是一个 StartEvent,StartEvent 是 FlowNode 的子类
        if (currentFlowElement instanceof FlowNode) {
            // 处理 FlowNode 流节点
            handleFlowNode((FlowNode) currentFlowElement);
        } else if (currentFlowElement instanceof SequenceFlow) {
            // 处理 SequenceFlow 系列流
            handleSequenceFlow();
        }
    }
    
    /**
     * uai 处理流节点
     * @param flowNode
     */
    protected void handleFlowNode(FlowNode flowNode) {
        // 记录 StartEvent 活动结束
        handleActivityEnd(flowNode);
        if (flowNode.getParentContainer() != null
                && flowNode.getParentContainer() instanceof AdhocSubProcess) {
            handleAdhocSubProcess(flowNode);
        } else {
            // StartEvent走这里, 离开流节点
            leaveFlowNode(flowNode);
        }
    }
    
    /**
     * 离开流节点
     * @param flowNode
     */
    protected void leaveFlowNode(FlowNode flowNode) {
        
        // 省略部分代码
        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> 实例,用来存储符合外出流条件的 SequenceFlow
        List<SequenceFlow> outgoingSequenceFlows = new ArrayList<SequenceFlow>();
        // 获取 StartEvent 节点可以外出的顺序流,并放到外出顺序流集合 outgoingSequenceFlows 中
        for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
            String skipExpressionString = sequenceFlow.getSkipExpression();
            // 通过 isSkipExpressionEnabled 判断 execution 是否开启了跳过表达式
            if (!SkipExpressionUtil.isSkipExpressionEnabled(execution, skipExpressionString)) {
    
                if (!evaluateConditions || (evaluateConditions && ConditionUtil.hasTrueCondition(sequenceFlow, execution)
                                        && (defaultSequenceFlowId == null || !defaultSequenceFlowId.equals(sequenceFlow.getId())))) {
                    // 符合外出流条件的放入到 outgoingSequenceFlows
                    outgoingSequenceFlows.add(sequenceFlow);
                }
            } else if (flowNode.getOutgoingFlows().size() == 1 || SkipExpressionUtil.shouldSkipFlowElement(commandContext,
                                                                                                           execution,
                                                                                                           skipExpressionString)) {
                // The 'skip' for a sequence flow means that we skip the condition, not the sequence flow.
                // 符合外出流条件的放入到 outgoingSequenceFlows
                outgoingSequenceFlows.add(sequenceFlow);
            }
        }
    
        // Check if there is a default sequence flow
        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
                        outgoingSequenceFlows.add(sequenceFlow);
                        break;
                    }
                }
            }
        }

        // No outgoing found. Ending the execution
        // 如果没有当前节点没有可以外出的顺序流,则流程到当前节点后,设置为结束。StartEvent不走这里
        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
            /**
             * uai
             * 给已经存在的execution(ExecutionEntity)实例更新状态,表示流程走到了 sequenceFlow 这个节点.
             * Process流程模型可以理解为一条高速公路,execution(ExecutionEntity)理解为一辆车,高速公路上有多个服务区,每个服务区是一个 sequenceFlow。
             * 现有一辆货车,我们规定它每走到一个服务区时车辆要加油或者司机要休息一下,在加油或者休息时司机需要把当前所在的服务区(sequenceFlow)告诉他的老板,让
             * 老板知道货运到哪里了(也就是在整个审批流程中,setCurrentFlowElement这一操作,让我们知道流程走到哪里了)
             */
            // 将 execution 中的 CurrentFlowElement 从之前的 StartEvent 更新为 SequenceFlow
            execution.setCurrentFlowElement(sequenceFlow);
            execution.setActive(true);
            // 将从 StartEvent 中出发的 execution 实例放入到 outgoingExecutions 链表中
            outgoingExecutions.add((ExecutionEntity) execution);
    
            // Executions for all the other one
            // 有多条出口,我的审批流程图中,StartEvent 只有一条外出流,所以不进入这个 if 语句
            if (outgoingSequenceFlows.size() > 1) {
                for (int i = 1; i < outgoingSequenceFlows.size(); i++) {
                    // 如果当前 execution 有 parent,则大家共用这个 parent,
                    // 如果当前 execution 没有 parent,则用当前 execution 作为 parent,
                    ExecutionEntity parent = execution.getParentId() != null ? execution.getParent() : execution;
                    // 根据 父ExecutionEntity 信息,创建 子ExecutionEntity 实例,相当于高速公里有分叉路
                    ExecutionEntity outgoingExecutionEntity = commandContext.getExecutionEntityManager().createChildExecution(parent);
    
                    SequenceFlow outgoingSequenceFlow = outgoingSequenceFlows.get(i);
                    // 给 子ExecutionEntity 实例设置当前节点为 outgoingSequenceFlow
                    outgoingExecutionEntity.setCurrentFlowElement(outgoingSequenceFlow);
                    // 存储到数据库
                    executionEntityManager.insert(outgoingExecutionEntity);
                    outgoingExecutions.add(outgoingExecutionEntity);
                }
            }
    
            // Leave (only done when all executions have been made, since some queries depend on this)
            // 把 outgoingExecution 放入到 Agenda 的队列中,计划离开当前节点,前往下一个节点
            // 这里可能有多个节点,所以通过遍历走所有的外出流,当前的审批流程图中,只有一条外出流,所以 outgoingExecutions 的大小是1
            for (ExecutionEntity outgoingExecution : outgoingExecutions) {
                // 准备执行 ContinueProcessOperation 操作
                Context.getAgenda().planContinueProcessOperation(outgoingExecution);
            }
        }
    }
}

        上面这个代码,最重要的是从 StartEvent 节点的信息中找到了外出流 (SequenceFlow),随即调用 execution setCurrentFlowElement 把活跃节点从之前的 StartEvent 更新为 SequenceFlow,这个操作表示流程从 StartEvent 走到了 SequenceFlow 这里。后续将从 SequenceFlow 继续走到下个节点。

        分析上面代码发现流程最终又走到了 Context.getAgenda().planContinueProcessOperation(ExecutionEntity) 方法去执行 ContinueProcessOperation 中的业务,是不是重复执行了?

        表面上看是重复执行了,但实际上有一些微妙的变化,这个变化是:传给 planContinueProcessOperation 方法的 execution 实例,它的 currentFlowElementStartEvent 变成了 SequenceFlow。这个变化就会使得流程进入到 ContinueProcessOperation else if 语句中,而不是第一次刚进来的 if 语句。

public class ContinueProcessOperation extends AbstractOperation {

    // 省略部分代码
    /**
     * 当 ContinueProcessOperation 操作被执行时,以 run 方法作为入口
     */
    @Override
    public void run() {
        // 第一次执行这个逻辑,取出来的 currentFlowElement 是一个 StartEvent,StartEvent 是 FlowNode 的子类
        FlowElement currentFlowElement = getCurrentFlowElement(execution);
        if (currentFlowElement instanceof FlowNode) {
            // 继续执行 FlowNode 类型的类,StartEvent会走这个方法
            continueThroughFlowNode((FlowNode) currentFlowElement);
        } else if (currentFlowElement instanceof SequenceFlow) {
            // 继续执行 SequenceFlow 类型的类
            continueThroughSequenceFlow((SequenceFlow) currentFlowElement);
        } else {
            throw new ActivitiException("Programmatic error: no current flow element found or invalid type: " + currentFlowElement + ". Halting.");
        }
    }
}

ContinueProcessOperation 操作(第二次)

构造 ContinueProcessOperation

        忽略阐述此重复内容。

执行 ContinueProcessOperation

        接上面的内容,流程进入到 ContinueProcessOperation else if 语句中,而不是第一次刚进来的 if 语句。

        else if 语句中调用的方法是 continueThroughSequenceFlow(SequenceFlow)。

/**
 * 执行 SequenceFlow 逻辑
 * @param sequenceFlow
 */
protected void continueThroughSequenceFlow(SequenceFlow sequenceFlow) {

    // Execution listener. Sequenceflow only 'take' makes sense ... but we've supported all three since the beginning
    // 执行 SequenceFlow 上的监听器
    if (CollectionUtil.isNotEmpty(sequenceFlow.getExecutionListeners())) {
        executeExecutionListeners(sequenceFlow,
                                  ExecutionListener.EVENTNAME_START);
        executeExecutionListeners(sequenceFlow,
                                  ExecutionListener.EVENTNAME_TAKE);
        executeExecutionListeners(sequenceFlow,
                                  ExecutionListener.EVENTNAME_END);
    }

    // Firing event that transition is being taken
    if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
        FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
        FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
        Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
                ActivitiEventBuilder.createSequenceFlowTakenEvent(
                        (ExecutionEntity) execution,
                        ActivitiEventType.SEQUENCEFLOW_TAKEN,
                        sequenceFlow.getId(),
                        sourceFlowElement != null ? sourceFlowElement.getId() : null,
                        sourceFlowElement != null ? (String) sourceFlowElement.getName() : null,
                        sourceFlowElement != null ? sourceFlowElement.getClass().getName() : null,
                        sourceFlowElement != null ? ((FlowNode) sourceFlowElement).getBehavior() : null,
                        targetFlowElement != null ? targetFlowElement.getId() : null,
                        targetFlowElement != null ? targetFlowElement.getName() : null,
                        targetFlowElement != null ? targetFlowElement.getClass().getName() : null,
                        targetFlowElement != null ? ((FlowNode) targetFlowElement).getBehavior() : null));
    }

    // 获取 sequenceFlow 的下一个节点
    FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
    // 更新 execution 当前所处的节点,前面更新过两次,第一次设置为 StartEvent,第二次设置为 SequenceFlow,当前第三次更新为审批流程图中的UserTask
    execution.setCurrentFlowElement(targetFlowElement);

    logger.debug("Sequence flow '{}' encountered. Continuing process by following it using execution {}",
                 sequenceFlow.getId(),
                 execution.getId());
    // 继续前往下个节点,在这里又执行了一次 planContinueProcessOperation
    Context.getAgenda().planContinueProcessOperation(execution);
}

        上面代码中,最后一行又是 Context.getAgenda().planContinueProcessOperation(ExecutionEntity) 方法,此方法去执行 ContinueProcessOperation 中的业务。这一次传给 planContinueProcessOperation 方法的 execution 实例,它的 currentFlowElement SequenceFlow 变成了 UserTask

ContinueProcessOperation 操作(第三次)

构造 ContinueProcessOperation

        忽略阐述此重复内容。

执行 ContinueProcessOperation

        UserTask StartEvent 一样,它也是 FlowNode 的子类,因此在 ContinueProcessOperation run 方法中,流程进入到 if 语句 中。

public class ContinueProcessOperation extends AbstractOperation {

    // 省略部分代码
    /**
     * 当 ContinueProcessOperation 操作被执行时,以 run 方法作为入口
     */
    @Override
    public void run() {
        // 第一次执行这个逻辑,取出来的 currentFlowElement 是一个 StartEvent,StartEvent 是 FlowNode 的子类
        FlowElement currentFlowElement = getCurrentFlowElement(execution);
        if (currentFlowElement instanceof FlowNode) {
            // 继续执行 FlowNode 类型的类,StartEvent会走这个方法
            continueThroughFlowNode((FlowNode) currentFlowElement);
        } else if (currentFlowElement instanceof SequenceFlow) {
            // 继续执行 SequenceFlow 类型的类
            continueThroughSequenceFlow((SequenceFlow) currentFlowElement);
        } else {
            throw new ActivitiException("Programmatic error: no current flow element found or invalid type: " + currentFlowElement + ". Halting.");
        }
    }
}

        进入后,大致逻辑和 StartEvent 相似,但不同的点在于 UserTask 上的节点行为是 UserTaskActivityBehavior,此行为不像 StartEvent NoneStartEventActivityBehavior 行为,UserTaskActivityBehavior 它定义了这个 UserTask 上的具体行为。在经过这个行为后,流程会暂时停在 UserTask 节点上,等待用户审批完成才会继续走下去。UserTask 节点的具体的行为见下一篇文章03 节点行为。下面这个代码和前面是重复的,为方便观察,所以粘贴一份。

/**
 * 同步执行
 * @param flowNode
 */
protected void executeSynchronous(FlowNode flowNode) {
    // 调用HistoryManager记录流程活动开始了,这里并不是单单指StartEvent活动,而是所有活动
    commandContext.getHistoryManager().recordActivityStart(execution);

    // Execution listener: event 'start'
    // 执行 StartEvent 上的监听器,发布 Start 的 Event 事件
    if (CollectionUtil.isNotEmpty(flowNode.getExecutionListeners())) {
        executeExecutionListeners(flowNode, ExecutionListener.EVENTNAME_START);
    }

    // Execute any boundary events, sub process boundary events will be executed from the activity behavior
    if (!inCompensation && flowNode instanceof Activity) { // Only activities can have boundary events
        // 获取节点上的边界事件
        List<BoundaryEvent> boundaryEvents = ((Activity) flowNode).getBoundaryEvents();
        if (CollectionUtil.isNotEmpty(boundaryEvents)) {
            executeBoundaryEvents(boundaryEvents, execution);
        }
    }

    // Execute actual behavior
    // 执行实际的行为,UserTask对应的behavior是UserTaskActivityBehavior,这个UserTaskActivityBehavior里面会把task写入到act_ru_task
    ActivityBehavior activityBehavior = (ActivityBehavior) flowNode.getBehavior();
    // 当 activityBehavior 不为空,走此方法,此方法后续也会调用 planTakeOutgoingSequenceFlowsOperation
    // activityBehavior 表示一个节点上拥有的行为
    // StartEvent 节点的行为是 NoneStartEventActivityBehavior,没有做其它业务,仅仅是过度
    // UserTask   节点的行为是 UserTaskActivityBehavior,这个行为会把任务写入到数据库后,等待用户完成任务,流程才会继续走下去
    if (activityBehavior != null) {
        executeActivityBehavior(activityBehavior, flowNode);
    } else {
        logger.debug("No activityBehavior on activity '{}' with execution {}", flowNode.getId(), execution.getId());
        // 计划执行 TakeOutgoingSequenceFlows 操作,这个操作是一个连线行为,第一步先找出当前节点的出口,第二步从出口走到下一个节点。
        Context.getAgenda().planTakeOutgoingSequenceFlowsOperation(execution, true);
    }
}

总结

        本章节内容有点绕也有点复杂,下面画个简图辅助理解。图中的 ExecutionEntity ProcessInstance 接口的实现类,所以 ExecutionEntity 本身就是 ProcessInstance 的一个实例,这个实例叫 流程实例。一个流程实例至少有一个或多个 ExecutionEntity 实例,流程实例本身称之为 Parent ExecutionEntity,而流程实例下的一个或多个 ExecutionEntity 称之为 Sub ExecutionEntity, 它们之间属于父子关系。像本章开头的审批流程图,因没有并行分支,所以只会产生一个 Sub ExecutionEntity

总结流程流转要点:
  1. 启动流程实例:创建 ExecutionEntity 的实例,并将此实例的 CurrentFlowElement 指向 StartEvent
  2. 流程流转到SequenceFlow:ExecutionEntity 流转到 SequenceFlow此时将 CurrentFlowElement 指向 SequenceFlow
  3. 流程流转到UserTask:ExecutionEntity 流转到 UserTask此时将 CurrentFlowElement 指向 UserTask
  4. 以此类推,当 ExecutionEntity 流转到 EndEvent 时,CurrentFlowElement 指向 EndEvent,标记此流程实例结束。
流程流转对应的示意图如下:


网站公告

今日签到

点亮在社区的每一天
去签到