服务热线
135-6963-3175
节点是怎么流转出线的呢?
主要做的操作: 主要做了如下操作: 检查是否补偿节点, 是: 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线);
貌似发现在TakeOutgoingSequenceFlowsOperation调用planContinueProcessOperation(execution线)参数都是seq线。
我们可以看TakeOutgoingSequenceFlowsOperation类的代码:
@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操作
若是个线条:执行handleSequenceFlow操作。
我们首先来分析步骤2源码:cleanupExecutions(currentFlowElement);
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);
}
}
}
}
}可以看到:
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
接下来分析步骤3:
handleFlowNode((FlowNode) currentFlowElement);
protected void handleFlowNode(FlowNode flowNode) {
handleActivityEnd(flowNode);//记录结束时间等信息及监听器的触发
if (flowNode.getParentContainer() != null
&& flowNode.getParentContainer() instanceof AdhocSubProcess) {//特别子流程
handleAdhocSubProcess(flowNode);
} else {
leaveFlowNode(flowNode);
}
}代码主要操作:
1、记录结束时间等信息及监听器的触发
2、若是特别子流程则处理
否则:离开节点
特别子流程处理:
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() == false) {//不取消剩余实例
List<ExecutionEntity> childExecutions = commandContext.getExecutionEntityManager().findChildExecutionsByParentExecutionId(execution.getParentId());
for (ExecutionEntity executionEntity : childExecutions) {
if (executionEntity.getId().equals(execution.getId()) == false) {
endAdhocSubProcess = false;
break;
}
}
}
if (endAdhocSubProcess) {//结束特殊子流程
Context.getAgenda().planEndExecutionOperation(execution.getParent());
}
}
}主要操作
如果有完成条件、判断条件是否满足
若出线大于0则执行出线leaveFlowNode()
出线为0则:执行删除执行相关数据操作(也就是可能是特殊子流程的最后一个节点了)
若满足完成条件:
判断:
若特殊子流程不取消剩余实例:
判断是否结束特殊子流程: 查找是否还有其他的子执行,若是则不结束;
若结束则:Context.getAgenda().planEndExecutionOperation(execution.getParent());
接下来分析leaveFlowNode(flowNode):
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 || //1条出线或配置必须跳过条件为true
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);
}
}
}分析代码,主要执行的操作:
获取默认序列流(如果设置)
获取所有出线的表达式并计算(两种情况:未开启跳过则进行表达式计算;1条出线或配置必须跳过条件为true)
确定哪些序列流可用于离开。
步骤2结果数为0且需计算条件(则从该节点所有出线里找出默认出线);
没有发现出线。结束执行。(Context.getAgenda().planEndExecutionOperation(execution节点))
否则:从集合获取第一条线设置active为true。
并对所有出线创建子执行execution,并对所有子执行进行: Context.getAgenda().planContinueProcessOperation(outgoingExecution线)操作。
分析步骤3handleSequenceFlow()方法:
protected void handleSequenceFlow() {
commandContext.getHistoryManager().recordActivityEnd(execution, null);
Context.getAgenda().planContinueProcessOperation(execution);
}主要进行操作:
1.更新结束信息(结束时间、花费时间、删除原因)
2.执行继续流程计划Context.getAgenda().planContinueProcessOperation(execution);