工作流系列--EndExecutionOperation源码解析

Posted by 张伟真 on 2024-11-10
Estimated Reading Time 7 Minutes
Words 1.7k In Total
Viewed Times

工作流系列–EndExecutionOperation源码解析

流程结束

流程终究会结束, 那流程是怎么结束的呢,这里涉及到一个关键的类,就是我们的EndExecutionOperation

省流直接看文章末尾总结
结束流程分析
主代码很简洁,就是2个分支,流程实例级别则走handleProcessInstanceExecution,否则走handleRegularExecution

handleProcessInstanceExecution分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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 {
//保存内嵌子流程的变量到库和执行实例execution
subProcessActivityBehavior.completing(superExecution, processInstanceExecution);
} 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);
}

// and trigger execution afterwards if doing a call activity
if (superExecution != null) {
superExecution.setSubProcessInstance(null);
try {
// 行为操作最终调用leave离开
subProcessActivityBehavior.completed(superExecution);
} catch (RuntimeException e) {
logger.error("Error while completing sub process of execution {}", rocessInstanceExecution, 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);
}
}
}

handleProcessInstanceExecution主要做了4件事情

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

接下来我们看handleRegularExecution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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);
}
}
}
}

handleRegularExecution也是做了4件事情

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

总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
若是流程实例级别:
1.找父实例
存在父执行:在销毁结束的子流程实例(callActivity)之前保存变量。(通过调用父执行当前元素的行为类的completing方法)
2.获取存活的子执行数量
2.1:通过流程实例id删除实例相关所有数据;
3.流程存在执行监听器则执行结束监听器;
4.存在父执行,父执行实例的子流程实例设置为null,并通过调用父执行元素活动行为类的completed用于离开;

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

如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !