activiti是原來不支援節點跳轉的,他要求有線才能走,但實際業務中,需要支援動态跳轉到各個節點。
一開始,這裡的做法是動态構造一條虛拟線的,相關代碼如下:
/**
* 流程轉向操作
*
* @param taskId
* 目前任務ID
* @param activityId
* 目标節點任務ID
* @param variables
* 流程變量
* @throws Exception
*/
public static void turnTransition(String taskId, String activityId, Map<String, Object> variables)
throws Exception {
TaskEntity taskEntitiy=findTaskById(taskId);
// 目前節點
ActivityImpl currActivity = findActivitiImpl(taskId, null);
// 清空目前流向
List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);
// 建立新流向
TransitionImpl newTransition = currActivity.createOutgoingTransition();
// 目标節點
ActivityImpl pointActivity = findActivitiImpl(taskId, activityId);
// 設定新流向的目标節點
newTransition.setDestination(pointActivity);
// 執行轉向任務
taskService.complete(taskId, variables);
// 删除目标節點新流入
pointActivity.getIncomingTransitions().remove(newTransition);
// 還原以前流向
restoreTransition(currActivity, oriPvmTransitionList);
}
這種情況一直好好的,但後續發現流程通過時,自動跳到前面的節點。
經查,原因是這樣的:
這種方法可以實作動态跳轉,不需要修改Activiti自身執行,但是會動态修改系統中的流程定義緩存對象。理論上這會出現一個多線程下,全局變量不安全的問題。單個Activiti流程引擎中,流程定義緩存對象是被所有線程共用的,當一個應用伺服器同時收到兩個不同流程執行個體、同個流程定義、同個環節的任務送出請求。a要求駁回,是以該線程動态修改了流程定義;與此同時,b要求正常流轉,但是執行過程中,依據的流程定義已被修改,可能導緻b也走向了駁回。
那怎麼整,上網查了一下,發現了
分享牛的代碼,但他的代碼存在問題,不支援多執行個體跳轉多執行個體。
後續将代碼修改如下:
package com.meicloud.meiqing.workflow.engine.operation.base;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.meicloud.meiqing.workflow.engine.constants.CdpActivitiConstant;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmException;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ScopeImpl;
import org.activiti.engine.impl.pvm.runtime.AtomicOperation;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;
/**
* @description: 自由跳轉流程
* @create: 2018-06-13 09:22
**/
public class JDJumpTaskCmd implements Command<Void> {
protected String taskId;//任務id
protected String executionId;//執行執行個體id
protected String parentId;//流程執行個體id
protected ActivityImpl desActivity;//目标節點
protected Map<String, Object> paramvar;//變量
protected ActivityImpl currentActivity;//目前的節點
@Override
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = Context
.getCommandContext().getExecutionEntityManager();
ExecutionEntity executionEntity = executionEntityManager
.findExecutionById(executionId);
//尋找根路徑
String id = null;
if (executionEntity.getParent() != null) {
executionEntity = executionEntity.getParent();
if (executionEntity.getParent() != null) {
executionEntity = executionEntity.getParent();
id = executionEntity.getId();
}
id = executionEntity.getId();
}
//設定相關變量
executionEntity.setVariables(paramvar);
//executionEntity.setExecutions(null);
executionEntity.setEventSource(this.currentActivity);
executionEntity.setActivity(this.currentActivity);
// 根據executionId 擷取Task
Iterator<TaskEntity> localIterator = Context.getCommandContext()
.getTaskEntityManager().findTasksByProcessInstanceId(parentId).iterator();
//删除無用的工作項
while (localIterator.hasNext()) {
TaskEntity taskEntity = (TaskEntity) localIterator.next();
System.err.println("==================" + taskEntity.getId());
if(taskId.equals(taskEntity.getId())) {
// 觸發任務監聽
taskEntity.fireEvent("complete");
// 删除任務的原因
Context.getCommandContext().getTaskEntityManager()
.deleteTask(taskEntity, "completed", false);
}else {
// 删除任務的原因
Context.getCommandContext().getTaskEntityManager()
.deleteTask(taskEntity, "deleted", false);
}
}
//删除相關執行子路徑,隻保留根執行路徑
List<ExecutionEntity> list = executionEntityManager
.findChildExecutionsByParentExecutionId(parentId);
for (ExecutionEntity executionEntity2 : list) {
ExecutionEntity findExecutionById = executionEntityManager.findExecutionById(executionEntity2.getId());
List<ExecutionEntity> parent = executionEntityManager
.findChildExecutionsByParentExecutionId(executionEntity2
.getId());
for (ExecutionEntity executionEntity3 : parent) {
executionEntity3.remove();
System.err.println(executionEntity3.getId()
+ "----------------->>>>>>>>>>");
Context.getCommandContext().getHistoryManager()
.recordActivityEnd(executionEntity3);
}
executionEntity2.remove();
Context.getCommandContext().getHistoryManager().recordActivityEnd(executionEntity2);
System.err.println(findExecutionById + "----------------->>>>>>>>>>");
}
commandContext
.getIdentityLinkEntityManager().deleteIdentityLinksByProcInstance(parentId);
//要激活交路徑
executionEntity.setActive(true);
//去掉無用的變量,不去掉,會導緻很多莫名奇妙的問題
executionEntity.removeVariable("loopCounter");
//去掉多執行個體的變量,如果變量不知道是啥,自己從節點定義裡查
executionEntity.removeVariable("cdp_atuser");
//觸發事件監聽器
this.execute(executionEntity);
InterpretableExecution propagatingExecution = null;
if (this.desActivity.isScope()) {
propagatingExecution = (InterpretableExecution) executionEntity.createExecution();
executionEntity.setTransition(null);
executionEntity.setActivity(null);
executionEntity.setActive(false);
// log.debug("create scope: parent {} continues as execution {}", execution, propagatingExecution);
propagatingExecution.initialize();
} else {
propagatingExecution = executionEntity;
}
propagatingExecution.executeActivity(this.desActivity);
return null;
}
protected ScopeImpl getScope(InterpretableExecution execution) {
return (ScopeImpl) execution.getActivity();
}
/*
觸發事件監聽器
*/
public void execute(InterpretableExecution execution) {
ScopeImpl scope = getScope(execution);
List<ExecutionListener> exectionListeners = scope.getExecutionListeners(getEventName());
for (ExecutionListener listener : exectionListeners) {
execution.setEventName(getEventName());
execution.setEventSource(scope);
try {
listener.notify(execution);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new PvmException("couldn't execute event listener : " + e.getMessage(), e);
}
}
}
protected String getEventName() {
return org.activiti.engine.impl.pvm.PvmEvent.EVENTNAME_END;
}
/**
* 構造參數 可以根據自己的業務需要添加更多的字段
* @param taskId
* @param executionId
* @param desActivity
* @param paramvar
* @param currentActivity
*/
public JDJumpTaskCmd(String taskId,String executionId, String parentId,
ActivityImpl desActivity, Map<String, Object> paramvar,
ActivityImpl currentActivity) {
this.taskId=taskId;
this.executionId = executionId;
this.parentId = parentId;
this.desActivity = desActivity;
this.paramvar = paramvar;
this.currentActivity = currentActivity;
}
}
經測試,功能正常!