天天看點

activiti多執行個體節點的任意跳轉

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;

    }
}

           

經測試,功能正常!

繼續閱讀