服务热线
135-6963-3175
启动流程实例涉及到的表有:
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、创建并触发开始事件,分发器调度消息事件订阅列表。
待补充...