启动流程实例涉及到的表有:
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、创建并触发开始事件,分发器调度消息事件订阅列表。
待补充...
Activiti社区交流群:839915498