工作流系列--TakeOutgoingSequenceFlowsOperation出线分析

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

工作流系列–planTakeOutgoingSequenceFlowsOperation出线分析

一、 分析

这节我们来看看planTakeOutgoingSequenceFlowsOperation出线究竟做来啥
省流总结直接看文档末尾
出线分析
源码中看出这里发出去TakeOutgoingSequenceFlowsOperation的命令,来看下命令里面怎么处理

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
@Override
public void run() {
FlowElement currentFlowElement = getCurrentFlowElement(execution);

// Compensation check 补偿检查
if ((currentFlowElement instanceof Activity)
&& (((Activity) currentFlowElement)).isForCompensation()) {

/*
* If the current flow element is part of a compensation, we don't always
* want to follow the regular rules of leaving an activity.
* More specifically, if there are no outgoing sequenceflow, we simply must stop
* the execution there and don't go up in the scopes as we usually do
* to find the outgoing sequenceflow
* 如果当前流程元素是补偿的一部分,我们并不总是希望遵循离开活动的常规规则。
* 更具体地说,如果没有传出序列流,我们只需在那里停止执行,而不是像我们通常做的那样在范围内找到传出序列流
*/

cleanupCompensation();
return;
}

// When leaving the current activity, we need to delete any related execution (eg active boundary events)
// 当离开当前活动时,我们需要删除任何相关的执行(例如活动边界事件)
cleanupExecutions(currentFlowElement);

if (currentFlowElement instanceof FlowNode) {
handleFlowNode((FlowNode) currentFlowElement);
} else if (currentFlowElement instanceof SequenceFlow) {
handleSequenceFlow();
}
}

上面做的主要事项
检查是否补偿节点:
是:的话则到这里停止执行,做清理操作并返回
否: 1、离开当前活动时候,要删除任务相关的执行(例如活动边界事件)
2、若是个节点:执行handleFlowNode操作
3、若是个线条:执行handleSequenceFlow操作。

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
protected void cleanupExecutions(FlowElement currentFlowElement) {
if (execution.getParentId() != null && execution.isScope()) {

// If the execution is a scope (and not a process instance), the scope must first be
// destroyed before we can continue and follow the sequence flow

Context.getAgenda().planDestroyScopeOperation(execution);
} else if (currentFlowElement instanceof Activity) {

// If the current activity is an activity, we need to remove any currently active boundary events

Activity activity = (Activity) currentFlowElement;
if (CollectionUtil.isNotEmpty(activity.getBoundaryEvents())) {

// Cancel events are not removed
List<String> notToDeleteEvents = new ArrayList<String>();
for (BoundaryEvent event : activity.getBoundaryEvents()) {
if (CollectionUtil.isNotEmpty(event.getEventDefinitions()) &&
event.getEventDefinitions().get(0) instanceof CancelEventDefinition) {
notToDeleteEvents.add(event.getId());
}
}

// Delete all child executions
Collection<ExecutionEntity> childExecutions = commandContext.getExecutionEntityManager().findChildExecutionsByParentExecutionId(execution.getId());
for (ExecutionEntity childExecution : childExecutions) {
if (childExecution.getCurrentFlowElement() == null || !notToDeleteEvents.contains(childExecution.getCurrentFlowElement().getId())) {
commandContext.getExecutionEntityManager().deleteExecutionAndRelatedData(childExecution,
null,
false);
}
}
}
}
}

看看cleanupExecutions主要做了啥呢
if. 当是一个父元素而非流程实例时候:则先销毁该元素范围内的,通过:Context.getAgenda().planDestroyScopeOperation(execution);
else 若是一个任务节点:更新(ACT_HI_ACTINST表)实例历史数据并删除子执行的相关数据(但不删除定义了边界取消事件的节点)
删除的子执行的数据有:
1.删除ACT_RU_IDENTITYLINK
2.删除ACT_RU_VARIABLE
3.删除ACT_GE_BYTEARRAY
4.删除ACT_RU_EXECUTION
主要是一些运行中的数据

下一步handleFlowNode

1
2
3
4
5
6
7
8
9
protected void handleFlowNode(FlowNode flowNode) {
handleActivityEnd(flowNode);
if (flowNode.getParentContainer() != null
&& flowNode.getParentContainer() instanceof AdhocSubProcess) {
handleAdhocSubProcess(flowNode);
} else {
leaveFlowNode(flowNode);
}
}

这里比较简单
1、记录结束时间等信息及监听器的触发
2、若是特别子流程则处理, 否则:离开节点
子流程怎么处理呢

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
protected void handleAdhocSubProcess(FlowNode flowNode) {
boolean completeAdhocSubProcess = false;
AdhocSubProcess adhocSubProcess = (AdhocSubProcess) flowNode.getParentContainer();
if (adhocSubProcess.getCompletionCondition() != null) {
Expression expression = Context.getProcessEngineConfiguration().getExpressionManager().createExpression(adhocSubProcess.getCompletionCondition());
Condition condition = new UelExpressionCondition(expression);
if (condition.evaluate(adhocSubProcess.getId(),
execution)) {
completeAdhocSubProcess = true;
}
}

if (flowNode.getOutgoingFlows().size() > 0) {
leaveFlowNode(flowNode);
} else {
commandContext.getExecutionEntityManager().deleteExecutionAndRelatedData(execution,
null,
false);
}

if (completeAdhocSubProcess) {
boolean endAdhocSubProcess = true;
if (!adhocSubProcess.isCancelRemainingInstances()) {
List<ExecutionEntity> childExecutions = commandContext.getExecutionEntityManager().findChildExecutionsByParentExecutionId(execution.getParentId());
for (ExecutionEntity executionEntity : childExecutions) {
if (!executionEntity.getId().equals(execution.getId())) {
endAdhocSubProcess = false;
break;
}
}
}

if (endAdhocSubProcess) {
Context.getAgenda().planEndExecutionOperation(execution.getParent());
}
}
}

如果有完成条件、判断条件是否满足
若出线大于0则执行出线leaveFlowNode()
出线为0则:执行删除执行相关数据操作(也就是可能是特殊子流程的最后一个节点了)
若满足完成条件,则判断:
若特殊子流程不取消剩余实例:
判断是否结束特殊子流程: 查找是否还有其他的子执行,若是则不结束;
若结束则:Context.getAgenda().planEndExecutionOperation(execution.getParent())

再看看leaveFlowNode

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
protected void leaveFlowNode(FlowNode flowNode) {

logger.debug("Leaving flow node {} with id '{}' by following it's {} outgoing sequenceflow",
flowNode.getClass(),
flowNode.getId(),
flowNode.getOutgoingFlows().size());

// Get default sequence flow (if set) 获取默认序列流(如果设置)
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> outgoingSequenceFlows = new ArrayList<SequenceFlow>();
//循环获取所有出线的表达式并计算
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
//获取跳过表达式
String skipExpressionString = sequenceFlow.getSkipExpression();
//_ACTIVITI_SKIP_EXPRESSION_ENABLED 全局变量是否开启跳过表达式
//未开启跳过表达式则计算
if (!SkipExpressionUtil.isSkipExpressionEnabled(execution,skipExpressionString)) {
//忽略计算条件(false)或者(条件表达式计算为true且(默认出现为null或非默认出线)
if (!evaluateConditions|| (evaluateConditions && ConditionUtil.hasTrueCondition(sequenceFlow,
execution) && (defaultSequenceFlowId == null || !defaultSequenceFlowId.equals(sequenceFlow.getId())))) {
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.
//序列流的“跳过”意味着我们跳过条件,而不是序列流。
//出线为1或者计算应该跳过流元素
outgoingSequenceFlows.add(sequenceFlow);
}
}

// Check if there is a default sequence flow 检查是否有默认的序列流,默认的加入出线集合
// 出线为0且需计算条件(找出默认出线)
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.add(sequenceFlow);
break;
}
}
}
}

// No outgoing found. Ending the execution 没有发现出线。结束执行
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
execution.setCurrentFlowElement(sequenceFlow);
execution.setActive(true);
outgoingExecutions.add((ExecutionEntity) execution);

// Executions for all the other one
//大于一个出线,则为所有的出线入库(并行网关等...)
if (outgoingSequenceFlows.size() > 1) {
for (int i = 1; i < outgoingSequenceFlows.size(); i++) {

ExecutionEntity parent = execution.getParentId() != null ? execution.getParent() : execution;
ExecutionEntity outgoingExecutionEntity = commandContext.getExecutionEntityManager().createChildExecution(parent);

SequenceFlow outgoingSequenceFlow = outgoingSequenceFlows.get(i);
outgoingExecutionEntity.setCurrentFlowElement(outgoingSequenceFlow);

executionEntityManager.insert(outgoingExecutionEntity);
outgoingExecutions.add(outgoingExecutionEntity);
}
}

// Leave (only done when all executions have been made, since some queries depend on this) 离开(仅在所有执行完成后才完成,因为某些查询依赖于此)
for (ExecutionEntity outgoingExecution : outgoingExecutions) {
Context.getAgenda().planContinueProcessOperation(outgoingExecution);
}
}
}

总的来说leaveFlowNode主要是以下4个点

  1. 获取默认序列流(如果设置)
  2. 获取所有出线的表达式并计算(两种情况:未开启跳过则进行表达式计算;1条出线或配置必须跳过条件为true)确定哪些序列流可用于离开。
  3. 步骤2结果数为0且需计算条件(则从该节点所有出线里找出默认出线);
  4. 没有发现出线。结束执行。(Context.getAgenda().planEndExecutionOperation(execution节点))否则:从集合获取第一条线设置active为true。
    并对所有出线创建子执行execution,并对所有子执行进行: Context.getAgenda().planContinueProcessOperation(outgoingExecution线)操作。

接下来是handleSequenceFlow

1
2
3
4
5
6
protected void handleSequenceFlow() {
// 更新结束信息(结束时间、花费时间、删除原因)
commandContext.getHistoryManager().recordActivityEnd(execution,null);
// 执行继续流程计划Context.getAgenda().planContinueProcessOperation(execution);
Context.getAgenda().planContinueProcessOperation(execution);
}

二、 总结

分析有点多,总的来说就是

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
检查是否补偿节点,
是:
1.到这里停止执行,做清理操作并返回。
否:
1.离开当前活动时候,要删除任务相关的执行(例如活动边界事件);
if. 当是一个父元素而非流程实例时候:则先销毁该元素范围内的,通过:Context.getAgenda().planDestroyScopeOperation(execution);
else 若是一个任务节点:更新(ACT_HI_ACTINST表)实例历史数据并删除子执行的相关数据(但不删除定义了边界取消事件的节点)
删除的子执行的数据有:
1.删除ACT_RU_IDENTITYLINK
2.删除ACT_RU_VARIABLE
3.删除ACT_GE_BYTEARRAY
4.删除ACT_RU_EXECUTION
2.判断节点类型
若是个节点:执行handleFlowNode操作:
a.记录结束时间等信息及监听器的触发
b.若是特别子流程:
1.如果有完成条件、判断条件是否满足
2.若出线大于0则:执行出线leaveFlowNode()
出线为0则:执行删除执行相关数据操作(也就是可能是特殊子流程的最后一个节点了)
3.若1满足完成条件:
判断:
若特殊子流程不取消剩余实例:
a.判断是否结束特殊子流程: 查找是否还有其他的子执行,若是则不结束;
b.若结束则:Context.getAgenda().planEndExecutionOperation(execution.getParent());
否则:leaveFlowNode操作:
1.获取默认序列流(如果设置)
2.获取所有出线的表达式并计算(两种情况:未开启跳过则进行表达式计算;1条出线或配置必须跳过条件为true)
3.确定哪些序列流可用于离开。
4.步骤2结果数为0且需计算条件(则从该节点所有出线里找出默认出线);
5.没有发现出线。结束执行。(Context.getAgenda().planEndExecutionOperation(execution节点))
否则:从集合获取第一条线设置active为true。
并对所有出线创建子执行execution,并对所有子执行进行:Context.getAgenda().planContinueProcessOperation(outgoingExecution线)操作。
若是个线条:执行handleSequenceFlow操作。
1.更新结束信息(结束时间、花费时间、删除原因)
2.执行继续流程计划Context.getAgenda().planContinueProcessOperation(execution线);

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