技术交流28群

服务热线

135-6963-3175

微信服务号

启动流程实例命令类源码解析 更新时间 2022-3-19 浏览2618次

启动流程实例涉及到的表有:

1、创建流程实例类型的执行实例入库ACT_RU_EXECUTION;
2、启动人入库ACT_RU_IDENTITYLINK starter类型;
3、历史启动实例记录(入库ACT_HI_PROCINST表)
4、dataObjects kv变量设置到流程实例变量map里 (存db(ACT_HI_VARINST历史变量实例表)或者更新缓存)
5、设置变量入库(入库ACT_RU_VARIABLE\(审计记录:入库ACT_HI_VARINST表)
6、针对事件子流程:ACT_RU_EXECUTION和ACT_RU_EVENT_SUBSCR

启动流程实例时候做了哪些操作呢?

主要看StartProcessInstanceCmd命令类:

public ProcessInstance execute(CommandContext commandContext) {
    DeploymentManager deploymentCache = commandContext.getProcessEngineConfiguration().getDeploymentManager();
    //1.查找流程定义
    // Find the process definition
    ProcessDefinition processDefinition = null;
    if (processDefinitionId != null) {
      processDefinition = deploymentCache.findDeployedProcessDefinitionById(processDefinitionId);
      if (processDefinition == null) {
        throw new ActivitiObjectNotFoundException("No process definition found for id = '" + processDefinitionId + "'", ProcessDefinition.class);
      }
    } else if (processDefinitionKey != null && (tenantId == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(tenantId))) {
      processDefinition = deploymentCache.findDeployedLatestProcessDefinitionByKey(processDefinitionKey);
      if (processDefinition == null) {
        throw new ActivitiObjectNotFoundException("No process definition found for key '" + processDefinitionKey + "'", ProcessDefinition.class);
      }
    } else if (processDefinitionKey != null && tenantId != null && !ProcessEngineConfiguration.NO_TENANT_ID.equals(tenantId)) {
      processDefinition = deploymentCache.findDeployedLatestProcessDefinitionByKeyAndTenantId(processDefinitionKey, tenantId);
      if (processDefinition == null) {
        throw new ActivitiObjectNotFoundException("No process definition found for key '" + processDefinitionKey + "' for tenant identifier " + tenantId, ProcessDefinition.class);
      }
    } else {
      throw new ActivitiIllegalArgumentException("processDefinitionKey and processDefinitionId are null");
    }
    //2.通过流程帮助类
    processInstanceHelper = commandContext.getProcessEngineConfiguration().getProcessInstanceHelper();
    ProcessInstance processInstance = createAndStartProcessInstance(processDefinition, businessKey, processInstanceName, variables, transientVariables);
    return processInstance;
  }

可以看到主要做了两个操作:

1、根据key或其他条件查找流程定义

2、流程帮助类的初始化,创建和启动流程实例

我们看下createAndStartProcessInstance

 protected ProcessInstance createAndStartProcessInstance(ProcessDefinition processDefinition, String businessKey, String processInstanceName, 
      Map<String,Object> variables, Map<String, Object> transientVariables) {
    return processInstanceHelper.createAndStartProcessInstance(processDefinition, businessKey, processInstanceName, variables, transientVariables);
  }

可以看到通过帮助类进行,继续看代码

   public ProcessInstance createAndStartProcessInstance(ProcessDefinition processDefinition,
      String businessKey, String processInstanceName, Map<String, Object> variables, Map<String, Object> transientVariables) {
    return createAndStartProcessInstance(processDefinition, businessKey, processInstanceName, variables, transientVariables, true);
  }
  //看调用:
  protected ProcessInstance createAndStartProcessInstance(ProcessDefinition processDefinition,
      String businessKey, String processInstanceName,
      Map<String, Object> variables, Map<String, Object> transientVariables, boolean startProcessInstance) {
    CommandContext commandContext = Context.getCommandContext(); // Todo: ideally, context should be passed here
    if (Activiti5Util.isActiviti5ProcessDefinition(commandContext, processDefinition)) {
      Activiti5CompatibilityHandler activiti5CompatibilityHandler = Activiti5Util.getActiviti5CompatibilityHandler();
      return activiti5CompatibilityHandler.startProcessInstance(processDefinition.getKey(), processDefinition.getId(),
          variables, businessKey, processDefinition.getTenantId(), processInstanceName);
    }
    // Do not start process a process instance if the process definition is suspended
    //查询流程定义是否挂起状态(如果流程定义被挂起,则不要启动流程实例)
    if (ProcessDefinitionUtil.isProcessDefinitionSuspended(processDefinition.getId())) {
      throw new ActivitiException("Cannot start process instance. Process definition " + processDefinition.getName() + " (id = " + processDefinition.getId() + ") is suspended");
    }
    // Get model from cache
    //通过缓存查process
    Process process = ProcessDefinitionUtil.getProcess(processDefinition.getId());
    if (process == null) {
      throw new ActivitiException("Cannot start process instance. Process model " + processDefinition.getName() + " (id = " + processDefinition.getId() + ") could not be found");
    }
    FlowElement initialFlowElement = process.getInitialFlowElement();
    if (initialFlowElement == null) {
      throw new ActivitiException("No start element found for process definition " + processDefinition.getId());
    }
    return createAndStartProcessInstanceWithInitialFlowElement(processDefinition, businessKey,
        processInstanceName, initialFlowElement, process, variables, transientVariables, startProcessInstance);
  }

主要操作:

1、若是activiti5标准则通过5引擎去启动返回,否则继续执行。

2、检查流程定义是否挂起状态(如果流程定义被挂起,则不要启动流程实例)

3、通过流程定义工具类查process(默认通过缓存查,出不到则查库)

注意:process的initialFlowElement初始化元素在流程定义解析期间StartEventParseHandler类里进行bpmnParse.getCurrentProcess().setInitialFlowElement(element);调用。也就是开始节点的元素startEvent。

4、创建和启动流程实例通过初始化元素

继续看createAndStartProcessInstanceWithInitialFlowElement代码:

/**
   *
   * @param processDefinition 流程定义
   * @param businessKey 业务键
   * @param processInstanceName 流程实例名称
   * @param initialFlowElement 初始流程元素
   * @param process
   * @param variables 变量
   * @param transientVariables 瞬态变量
   * @param startProcessInstance 是否启动流程实例
   * @return
   */
  public ProcessInstance createAndStartProcessInstanceWithInitialFlowElement(ProcessDefinition processDefinition,
      String businessKey, String processInstanceName, FlowElement initialFlowElement,
      Process process, Map<String, Object> variables, Map<String, Object> transientVariables, boolean startProcessInstance) {
    CommandContext commandContext = Context.getCommandContext();
    // Create the process instance
    String initiatorVariableName = null;
    if (initialFlowElement instanceof StartEvent) {//获取(发起)启动人变量
      initiatorVariableName = ((StartEvent) initialFlowElement).getInitiator();
    }
    //1.创建流程实例类型的执行实例初始化属性,(initiator:authenticatedUserId),入库ACT_RU_EXECUTION;
    //2.启动人获取到并入库ACT_RU_IDENTITYLINK starter类型;
    ExecutionEntity processInstance = commandContext.getExecutionEntityManager()
    .createProcessInstanceExecution(processDefinition, businessKey, processDefinition.getTenantId(), initiatorVariableName);
    //3.历史启动实例记录(入库ACT_HI_PROCINST表)
    commandContext.getHistoryManager().recordProcessInstanceStart(processInstance, initialFlowElement);
    //dataObjects kv变量设置到流程实例变量map里 (存db或者更新缓存)
    processInstance.setVariables(processDataObjects(process.getDataObjects()));
    // Set the variables passed into the start command
    if (variables != null) {//设置变量入库(入库ACT_RU_VARIABLE\(审计记录:入库ACT_HI_VARINST表,默认记录)\放入变量实例集合map)或更新缓存
      for (String varName : variables.keySet()) {
        processInstance.setVariable(varName, variables.get(varName));
      }
    }
    //设置临时变量,不入库
    if (transientVariables != null) {
      for (String varName : transientVariables.keySet()) {
        processInstance.setTransientVariable(varName, transientVariables.get(varName));
      }
    }
    //设置流程实例名称
    // Set processInstance name
    if (processInstanceName != null) {
      processInstance.setName(processInstanceName);
      commandContext.getHistoryManager().recordProcessInstanceNameChange(processInstance.getId(), processInstanceName);
    }
    // Fire events
    if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
      Context.getProcessEngineConfiguration().getEventDispatcher()
        .dispatchEvent(ActivitiEventBuilder.createEntityWithVariablesEvent(ActivitiEventType.ENTITY_INITIALIZED, processInstance, variables, false));
    }
    //访问所有的流程定义元素然后创建第一个执行execution
    // Create the first execution that will visit all the process definition elements
    ExecutionEntity execution = commandContext.getExecutionEntityManager().createChildExecution(processInstance);
    //设置当前元素为startEvent
    execution.setCurrentFlowElement(initialFlowElement);
    
    if (startProcessInstance) {
      //启动流程实例
        startProcessInstance(processInstance, commandContext, variables);
      }
      return processInstance;
    }

上面方法主要进行了:

1、创建流程实例类型的执行实例初始化属性,(initiator:authenticatedUserId),入库ACT_RU_EXECUTION;启动人获取到并入库ACT_RU_IDENTITYLINK starter类型;
2、历史启动实例记录(入库ACT_HI_PROCINST表)
3、dataObjects kv变量设置到流程实例变量map里 (存db或者更新缓存)
4、设置变量入库(入库ACT_RU_VARIABLE\(审计记录:入库ACT_HI_VARINST表,默认记录)\放入变量实例集合map)或更新缓存
5、设置临时变量,不入库(processInstance.setTransientVariable(varName, transientVariables.get(varName));)
6、设置流程实例名称
7、访问所有的流程定义元素然后创建第一个执行execution
8、execution设置当前元素为startEvent
9、启动流程实例:startProcessInstance(processInstance, commandContext, variables);

我们主要看步骤9

/**
   *
   * @param processInstance 流程实例
   * @param commandContext 命令上下文
   * @param variables 变量集
   */
    public void startProcessInstance(ExecutionEntity processInstance, CommandContext commandContext, Map<String, Object> variables) {
      Process process = ProcessDefinitionUtil.getProcess(processInstance.getProcessDefinitionId());
    // Event sub process handling   处理事件子流程(通过事件触发的流程、必须又一个开始事件节点并定义了触发事件):
      //                                1、创建子流程子执行实例(子执行针对startEvent开始事件)、获取定义的消息事件然后入库
      //                                2、入库ACT_RU_EVENT_SUBSCR
      List<MessageEventSubscriptionEntity> messageEventSubscriptions = new LinkedList<>();
    for (FlowElement flowElement : process.getFlowElements()) {
      if (flowElement instanceof EventSubProcess) {//当事件子流程
        EventSubProcess eventSubProcess = (EventSubProcess) flowElement;
        for (FlowElement subElement : eventSubProcess.getFlowElements()) {
          if (subElement instanceof StartEvent) {//开始事件
            StartEvent startEvent = (StartEvent) subElement;
            if (CollectionUtil.isNotEmpty(startEvent.getEventDefinitions())) {
              EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0);
              if (eventDefinition instanceof MessageEventDefinition) {
                //1.获取message消息定义事件
                MessageEventDefinition messageEventDefinition = (MessageEventDefinition) eventDefinition;
                BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processInstance.getProcessDefinitionId());
                if (bpmnModel.containsMessageId(messageEventDefinition.getMessageRef())) {
                  //给消息事件设置消息名称
                  messageEventDefinition.setMessageRef(bpmnModel.getMessage(messageEventDefinition.getMessageRef()).getName());
                }
                //2.创建流程实例子执行(给流程实例创建一个新的(针对开始事件的)子执行.并初始化属性定义信息、实例信息,并入库ACT_RU_EXECUTION入库)
                ExecutionEntity messageExecution = commandContext.getExecutionEntityManager().createChildExecution(processInstance);
                //设置当前元素为startEvent
                messageExecution.setCurrentFlowElement(startEvent);
                messageExecution.setEventScope(true);//事件范围
                //消息启动事件订阅
                messageEventSubscriptions
                        //3.入库ACT_RU_EVENT_SUBSCR,并把该事件加入上面创建的子执行的消息事件列表
                .add(commandContext.getEventSubscriptionEntityManager().insertMessageEvent(messageEventDefinition.getMessageRef(), messageExecution));
              }
            }
          }
        }
      }
    }
    
    ExecutionEntity execution = processInstance.getExecutions().get(0); // There will always be one child execution created 总会创建一个子执行
    commandContext.getAgenda().planContinueProcessOperation(execution);
    if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
    ActivitiEventDispatcher eventDispatcher = Context.getProcessEngineConfiguration().getEventDispatcher();
    //创建并触发开始事件
        eventDispatcher.dispatchEvent(ActivitiEventBuilder.createProcessStartedEvent(execution, variables, false));
        
        for (MessageEventSubscriptionEntity messageEventSubscription : messageEventSubscriptions) {
          //分发器调度消息事件订阅列表
            commandContext.getProcessEngineConfiguration().getEventDispatcher()
                    .dispatchEvent(ActivitiEventBuilder.createMessageEvent(ActivitiEventType.ACTIVITY_MESSAGE_WAITING, messageEventSubscription.getActivityId(),
                            messageEventSubscription.getEventName(), null, messageEventSubscription.getExecution().getId(),
                            messageEventSubscription.getProcessInstanceId(), messageEventSubscription.getProcessDefinitionId()));
          }
    }
  }

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

1、处理事件子流程(通过事件触发的流程、必须有一个开始事件节点并定义了触发事件):

      1.1 获取开始事件定义的消息事件(只能是MessageEventDefinition消息事件定义)。

      1.2 创建流程实例子执行

          (给流程实例创建一个新的(针对开始事件的)子执行.

           并初始化属性定义信息、实例信息,并入库ACT_RU_EXECUTION入库

      1.3 消息启动订阅入库ACT_RU_EVENT_SUBSCR

2、执行流程继续计划任务

    commandContext.getAgenda().planContinueProcessOperation(execution);

3、创建并触发开始事件,分发器调度消息事件订阅列表。


待补充...