最近在项目开发中需要在多实例开始监听里修改一个全局的计数变量,不太确定并行多实例任务在底层引擎是顺序生成还是并行生成的,如果是顺序生成的则不影响,如果是并行生成 则修改一个全局的计数变量就会出现数据错误问题,查阅了flowable源码,做个记录。
查看并行多实例节点任务类 ParallelMultiInstanceBehavior,代码如下:
protected int createInstances(DelegateExecution multiInstanceRootExecution) {
int nrOfInstances = resolveNrOfInstances(multiInstanceRootExecution);
if (nrOfInstances < 0) {
throw new FlowableIllegalArgumentException("Invalid number of instances: must be non-negative integer value" + ", but was " + nrOfInstances);
}
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_INSTANCES, nrOfInstances);
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_COMPLETED_INSTANCES, 0);
setLoopVariable(multiInstanceRootExecution, NUMBER_OF_ACTIVE_INSTANCES, nrOfInstances);
List<ExecutionEntity> concurrentExecutions = new ArrayList<>();
for (int loopCounter = 0; loopCounter < nrOfInstances; loopCounter++) {
ExecutionEntity concurrentExecution = CommandContextUtil.getExecutionEntityManager()
.createChildExecution((ExecutionEntity) multiInstanceRootExecution);
concurrentExecution.setCurrentFlowElement(activity);
concurrentExecution.setActive(true);
concurrentExecution.setScope(false);
concurrentExecutions.add(concurrentExecution);
logLoopDetails(concurrentExecution, "initialized", loopCounter, 0, nrOfInstances, nrOfInstances);
//CommandContextUtil.getHistoryManager().recordActivityStart(concurrentExecution);
}
// Before the activities are executed, all executions MUST be created up front
// Do not try to merge this loop with the previous one, as it will lead
// to bugs, due to possible child execution pruning.
for (int loopCounter = 0; loopCounter < nrOfInstances; loopCounter++) {
ExecutionEntity concurrentExecution = concurrentExecutions.get(loopCounter);
// executions can be inactive, if instances are all automatics
// (no-waitstate) and completionCondition has been met in the meantime
if (concurrentExecution.isActive()
&& !concurrentExecution.isEnded()
&& !concurrentExecution.getParent().isEnded()) {
executeOriginalBehavior(concurrentExecution, (ExecutionEntity) multiInstanceRootExecution, loopCounter);
}
}
// See ACT-1586: ExecutionQuery returns wrong results when using multi
// instance on a receive task The parent execution must be set to false, so it wouldn't show up in
// the execution query when using .activityId(something). Do not we cannot nullify the
// activityId (that would have been a better solution), as it would break boundary event behavior.
if (!concurrentExecutions.isEmpty()) {
multiInstanceRootExecution.setActive(false);
}
return nrOfInstances;
}
通过源码可以看出,并行多实例任务底层还是按顺序生成的,并不是并行生成。
以下是 该类的结构图:
可以看出该类是继承 FlowNodeActivityBehavior 类,以下是FlowNodeActivityBehavior的源码:
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flowable.engine.impl.bpmn.behavior;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.delegate.TriggerableActivityBehavior;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
/**
* Superclass for all 'connectable' BPMN 2.0 process elements: tasks, gateways and events. This means that any subclass can be the source or target of a sequenceflow.
*
* Corresponds with the notion of the 'flownode' in BPMN 2.0.
*
* @author Joram Barrez
*/
public abstract class FlowNodeActivityBehavior implements TriggerableActivityBehavior {
private static final long serialVersionUID = 1L;
protected BpmnActivityBehavior bpmnActivityBehavior = new BpmnActivityBehavior();
/**
* Default behaviour: just leave the activity with no extra functionality.
*/
@Override
public void execute(DelegateExecution execution) {
leave(execution);
}
/**
* Default way of leaving a BPMN 2.0 activity: evaluate the conditions on the outgoing sequence flow and take those that evaluate to true.
*/
public void leave(DelegateExecution execution) {
bpmnActivityBehavior.performDefaultOutgoingBehavior((ExecutionEntity) execution);
}
public void leaveIgnoreConditions(DelegateExecution execution) {
bpmnActivityBehavior.performIgnoreConditionsOutgoingBehavior((ExecutionEntity) execution);
}
@Override
public void trigger(DelegateExecution execution, String signalName, Object signalData) {
// concrete activity behaviours that do accept signals should override this method;
throw new FlowableException("this activity isn't waiting for a trigger");
}
protected String parseActivityType(FlowNode flowNode) {
String elementType = flowNode.getClass().getSimpleName();
elementType = elementType.substring(0, 1).toLowerCase() + elementType.substring(1);
return elementType;
}
}
FlowNodeActivityBehavior是流节点活动行为类,是所有“可连接”BPMN 2.0流程元素的超类:任务、网关和事件。这意味着任何子类都可以是sequenceflow的源或目标。与BPMN 2.0中的“流节点”(flownode)概念相对应。
FlowNodeActivityBehavior 的职责和作用
-
定义流程节点的行为:
FlowNodeActivityBehavior
接口定义了处理流程节点的标准行为,例如开始、结束、分支等。- 实现这个接口的类负责处理特定类型的流程节点,比如服务任务、用户任务、网关等。
-
执行流程节点的逻辑:
- 当流程执行器到达某个流程节点时,它会查找该节点的行为实现,并调用相应的方法来执行节点的逻辑。
- 这些方法包括但不限于
execute
、leave
等,它们负责处理节点的进入、执行和离开等操作。
-
支持不同类型的流程节点:
- 不同类型的流程节点会有不同的行为实现,例如用户任务和服务任务会有各自的实现类。
- 例如,用户任务的行为实现类可能需要处理用户界面交互,而服务任务的行为实现类则可能需要调用外部系统的服务。
关键方法
FlowNodeActivityBehavior
接口包含以下方法:
- execute(Execution execution): 负责执行流程节点的主要逻辑。当流程执行器到达该节点时,会调用此方法。
- leave(Execution execution): 负责在流程节点执行完成后离开该节点的操作。这通常涉及到更新执行状态、触发后续路径等。