Activiti啓動流程源碼解析

Activit啓動流程主要有兩種方式:java

一、利用FormService啓動:express

public ProcessInstance submitStartFormData(String processDefinitionId, String businessKey, Map<String, String> properties) {
        return (ProcessInstance)this.commandExecutor.execute(new SubmitStartFormCmd(processDefinitionId, businessKey, properties));
    }

二、利用RuntimeService啓動:設計模式

public ProcessInstance startProcessInstanceById(String processDefinitionId, String businessKey, Map<String, Object> variables) {
        return (ProcessInstance)this.commandExecutor.execute(new StartProcessInstanceCmd((String)null, processDefinitionId, businessKey, variables));
    }

二者有個重要區別:異步

formService.submitStartFormData方法的第三個參數是限定了Map<String, String>類型的變量,而runtimeService.startProcessInstanceById方法的第三個參數類型爲Map<String, Object>。這就意味着後者的參數類型適用範圍更廣,若是須要傳遞除String類型的變量外時推薦使用後者(如在發起流程後,緊接着一個會籤節點,而此時須要傳遞assigneeList辦理人數據變量就只能用後者啓動了)。ide

此外,前者主要仍是用於動態表單、外置表單類型的流程啓動。後者用於普通表單類型的流程啓動。二者本質區別是:前者會去解析表單字段,然後者不會,其餘流程基本一致。 本篇將首先去解析formService.submitStartFormData啓動流程的方法源碼。學習

一、該啓動方法共有兩種重載形式:ui

public ProcessInstance submitStartFormData(String processDefinitionId, Map<String, String> properties) {
        return (ProcessInstance)this.commandExecutor.execute(new SubmitStartFormCmd(processDefinitionId, (String)null, properties));
    }

    public ProcessInstance submitStartFormData(String processDefinitionId, String businessKey, Map<String, String> properties) {
        return (ProcessInstance)this.commandExecutor.execute(new SubmitStartFormCmd(processDefinitionId, businessKey, properties));
    }

區別僅在因而否須要傳遞businessKey參數(通常而言作實際業務時都是須要的),所以咱們着重看第二種形式。this

public ProcessInstance submitStartFormData(String processDefinitionId, String businessKey, Map<String, String> properties) {
        return (ProcessInstance)this.commandExecutor.execute(new SubmitStartFormCmd(processDefinitionId, businessKey, properties));
    }

Activiti是一種典型的責任鏈+命令的設計模式,使得新手比較難於跟蹤源碼,建議有時間的話先去學習下這兩種設計模式。 可是這種設計的好處也很明顯,使得咱們在對Activiti進行功能需求自定義或者擴展時顯得異常方便。 好了,廢話很少說,這裏面具體的實現者是SubmitStartFormCmd這個命令類,跟進去看源碼:spa

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.activiti.engine.impl.cmd;

import java.util.Map;
import org.activiti.engine.impl.form.StartFormHandler;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.runtime.ProcessInstance;

public class SubmitStartFormCmd extends NeedsActiveProcessDefinitionCmd<ProcessInstance> {
    private static final long serialVersionUID = 1L;
    protected final String businessKey;
    protected Map<String, String> properties;

    public SubmitStartFormCmd(String processDefinitionId, String businessKey, Map<String, String> properties) {
        super(processDefinitionId);
        this.businessKey = businessKey;
        this.properties = properties;
    }

    protected ProcessInstance execute(CommandContext commandContext, ProcessDefinitionEntity processDefinition) {
        ExecutionEntity processInstance = null;
        if (this.businessKey != null) {
            processInstance = processDefinition.createProcessInstance(this.businessKey);
        } else {
            processInstance = processDefinition.createProcessInstance();
        }

        commandContext.getHistoryManager().reportFormPropertiesSubmitted(processInstance, this.properties, (String)null);
        StartFormHandler startFormHandler = processDefinition.getStartFormHandler();
        startFormHandler.submitFormProperties(this.properties, processInstance);
        processInstance.start();
        return processInstance;
    }
}

這個命令類只有一個構造方法和一個execute方法,重點就是這個execute方法了:線程

protected ProcessInstance execute(CommandContext commandContext, ProcessDefinitionEntity processDefinition) {
        ExecutionEntity processInstance = null;
        if (this.businessKey != null) {//這裏便是對兩種重載方法的兼容處理
            processInstance = processDefinition.createProcessInstance(this.businessKey);
        } else {
            processInstance = processDefinition.createProcessInstance();
        }

        commandContext.getHistoryManager().reportFormPropertiesSubmitted(processInstance, this.properties, (String)null);
        StartFormHandler startFormHandler = processDefinition.getStartFormHandler();
        startFormHandler.submitFormProperties(this.properties, processInstance);
        processInstance.start();
        return processInstance;
    }

看下這步:

processInstance = processDefinition.createProcessInstance(this.businessKey);

其源碼:

public ExecutionEntity createProcessInstance(String businessKey) {
       return this.createProcessInstance(businessKey, (ActivityImpl)null);
   }

繼續:

public ExecutionEntity createProcessInstance(String businessKey, ActivityImpl initial) {
        ExecutionEntity processInstance = null;
        if (initial == null) {
            processInstance = (ExecutionEntity)super.createProcessInstance();
        } else {
            processInstance = (ExecutionEntity)super.createProcessInstanceForInitial(initial);
        }

        processInstance.setExecutions(new ArrayList());
        processInstance.setProcessDefinition(this.processDefinition);
        if (businessKey != null) {
            processInstance.setBusinessKey(businessKey);
        }

        if (this.getTenantId() != null) {
            processInstance.setTenantId(this.getTenantId());
        }

        processInstance.setProcessInstance(processInstance);
        Map<String, Object> dataObjectVars = this.getVariables();
        if (dataObjectVars != null) {
            processInstance.setVariables(dataObjectVars);
        }

        String authenticatedUserId = Authentication.getAuthenticatedUserId();
        String initiatorVariableName = (String)this.getProperty("initiatorVariableName");
        if (initiatorVariableName != null) {
            processInstance.setVariable(initiatorVariableName, authenticatedUserId);
        }

        if (authenticatedUserId != null) {
            processInstance.addIdentityLink(authenticatedUserId, (String)null, "starter");
        }

        Context.getCommandContext().getHistoryManager().recordProcessInstanceStart(processInstance);
        if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
            Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, processInstance));
        }

        return processInstance;
    }

先然,這個方法的目的就是構造一個流程實例對象ExecutionEntity,都是一些屬性的賦值,其中有一點須要注意下:

String authenticatedUserId = Authentication.getAuthenticatedUserId();
  if (authenticatedUserId != null) {
            processInstance.addIdentityLink(authenticatedUserId, (String)null, "starter");
        }

其中Authentication.getAuthenticatedUserId()這個是在哪裏取的流程啓動的用戶ID的呢?看其源碼:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.activiti.engine.impl.identity;

public abstract class Authentication {
    static ThreadLocal<String> authenticatedUserIdThreadLocal = new ThreadLocal();

    public Authentication() {
    }

    public static void setAuthenticatedUserId(String authenticatedUserId) {
        authenticatedUserIdThreadLocal.set(authenticatedUserId);
    }

    public static String getAuthenticatedUserId() {
        return (String)authenticatedUserIdThreadLocal.get();
    }
}

原來這個類就是拿來存放線程的局部變量的,Activiti用於存放辦理用戶的信息,便於隨時取出使用,剛纔咱們已經看到了流程在啓動時會去取出它的值做爲流程的啓動用戶,那這個值是何時放進去的呢?答案是:在調用啓動流程的方法以前,須要先調用下面這句代碼:

// 流程與用戶ID綁定
identityService.setAuthenticatedUserId(in.getUserId().toString());

好了,這就很清晰了。咱們接着createProcessInstance看這個方法:

if (authenticatedUserId != null) {
            processInstance.addIdentityLink(authenticatedUserId, (String)null, "starter");
        }

(關於addIdentityLink的源碼後面有空會單獨分析,這裏不展開敘述)這一步就是說若是啓動用戶取得出來,就在act_ru_identitylink和act_hi_identitylink中插入一條數據並標記爲流程的「starter」。

Context.getCommandContext().getHistoryManager().recordProcessInstanceStart(processInstance);

這個就是往流程的act_hi_comment表裏塞條數據,記錄流程啓動的相關信息。

if (Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
            Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, processInstance));
        }

這個就是流程啓動後會分發一個事件,這個事件能夠在監聽器中攔截到。至此,這個processDefinition.createProcessInstance(this.businessKey)方法咱們就分析完畢了,就是新建了個流程實例對象,並在act_ru_identitylink、act_hi_identitylink表裏記錄了流程啓動的用戶信息和在act_hi_comment表裏記錄了流程的啓動相關信息; 接着:

commandContext.getHistoryManager().reportFormPropertiesSubmitted(processInstance, this.properties, (String)null);

看源碼:

public void reportFormPropertiesSubmitted(ExecutionEntity processInstance, Map<String, String> properties, String taskId) {
        if (this.isHistoryLevelAtLeast(HistoryLevel.AUDIT)) {
            Iterator var4 = properties.keySet().iterator();

            while(var4.hasNext()) {
                String propertyId = (String)var4.next();
                String propertyValue = (String)properties.get(propertyId);
                HistoricFormPropertyEntity historicFormProperty = new HistoricFormPropertyEntity(processInstance, propertyId, propertyValue, taskId);
                this.getDbSqlSession().insert(historicFormProperty);
            }
        }

    }

意思是遍歷傳進來的Map變量把他們存在act_hi_detail表裏;接着:

StartFormHandler startFormHandler = processDefinition.getStartFormHandler();
startFormHandler.submitFormProperties(this.properties, processInstance);\

看submitFormProperties的源碼:

public void submitFormProperties(Map<String, String> properties, ExecutionEntity execution) {
        Map<String, String> propertiesCopy = new HashMap(properties);
        Iterator var4 = this.formPropertyHandlers.iterator();

        while(var4.hasNext()) {
            FormPropertyHandler formPropertyHandler = (FormPropertyHandler)var4.next();
            formPropertyHandler.submitFormProperty(execution, propertiesCopy);
        }

        var4 = propertiesCopy.keySet().iterator();

        while(var4.hasNext()) {
            String propertyId = (String)var4.next();
            execution.setVariable(propertyId, propertiesCopy.get(propertyId));
        }

    }

這步:Map<String, String> propertiesCopy = new HashMap(properties); 把變量複製到新的Map中,目的是:防止持有老對象的引用,操做時改變了原有變量值。

while(var4.hasNext()) {
            FormPropertyHandler formPropertyHandler = (FormPropertyHandler)var4.next();
            formPropertyHandler.submitFormProperty(execution, propertiesCopy);
        }

看submitFormProperty源碼:

public void submitFormProperty(ExecutionEntity execution, Map<String, String> properties) {
       if (!this.isWritable && properties.containsKey(this.id)) {
           throw new ActivitiException("form property '" + this.id + "' is not writable");
       } else if (this.isRequired && !properties.containsKey(this.id) && this.defaultExpression == null) {
           throw new ActivitiException("form property '" + this.id + "' is required");
       } else {
           boolean propertyExits = false;
           Object modelValue = null;
           if (properties.containsKey(this.id)) {
               propertyExits = true;
               String propertyValue = (String)properties.remove(this.id);
               if (this.type != null) {
                   modelValue = this.type.convertFormValueToModelValue(propertyValue);
               } else {
                   modelValue = propertyValue;
               }
           } else if (this.defaultExpression != null) {
               Object expressionValue = this.defaultExpression.getValue(execution);
               if (this.type != null && expressionValue != null) {
                   modelValue = this.type.convertFormValueToModelValue(expressionValue.toString());
               } else if (expressionValue != null) {
                   modelValue = expressionValue.toString();
               } else if (this.isRequired) {
                   throw new ActivitiException("form property '" + this.id + "' is required");
               }
           }

           if (propertyExits || modelValue != null) {
               if (this.variableName != null) {
                   execution.setVariable(this.variableName, modelValue);
               } else if (this.variableExpression != null) {
                   this.variableExpression.setValue(modelValue, execution);
               } else {
                   execution.setVariable(this.id, modelValue);
               }
           }

       }
   }

這裏主要是activiti對變量進行內置表單類型解析,其中此版本的Activiti只支持這麼幾種表單字段類型: TIM截圖20180705162238.png

而後利用以下代碼:

if (propertyExits || modelValue != null) {
                if (this.variableName != null) {
                    execution.setVariable(this.variableName, modelValue);
                } else if (this.variableExpression != null) {
                    this.variableExpression.setValue(modelValue, execution);
                } else {
                    execution.setVariable(this.id, modelValue);
                }
            }

會將變量存在act_ru_variable、act_hi_varinst中。

protected void updateVariableInstance(VariableInstanceEntity variableInstance, Object value, ExecutionEntity sourceActivityExecution) {
        VariableTypes variableTypes = Context.getProcessEngineConfiguration().getVariableTypes();
        VariableType newType = variableTypes.findVariableType(value);
        if (variableInstance != null && !variableInstance.getType().equals(newType)) {
            variableInstance.setValue((Object)null);
            variableInstance.setType(newType);
            variableInstance.forceUpdate();
            variableInstance.setValue(value);
        } else {
            variableInstance.setValue(value);
        }

        Context.getCommandContext().getHistoryManager().recordHistoricDetailVariableCreate(variableInstance, sourceActivityExecution, this.isActivityIdUsedForDetails());
        Context.getCommandContext().getHistoryManager().recordVariableUpdate(variableInstance);
    }

其中recordHistoricDetailVariableCreate源碼:

public void recordHistoricDetailVariableCreate(VariableInstanceEntity variable, ExecutionEntity sourceActivityExecution, boolean useActivityId) {
        if (this.isHistoryLevelAtLeast(HistoryLevel.FULL)) {
            HistoricDetailVariableInstanceUpdateEntity historicVariableUpdate = HistoricDetailVariableInstanceUpdateEntity.copyAndInsert(variable);
            if (useActivityId && sourceActivityExecution != null) {
                HistoricActivityInstanceEntity historicActivityInstance = this.findActivityInstance(sourceActivityExecution);
                if (historicActivityInstance != null) {
                    historicVariableUpdate.setActivityInstanceId(historicActivityInstance.getId());
                }
            }
        }

    }

recordVariableUpdate源碼:

public void recordVariableUpdate(VariableInstanceEntity variable) {
        if (this.isHistoryLevelAtLeast(HistoryLevel.ACTIVITY)) {
            HistoricVariableInstanceEntity historicProcessVariable = (HistoricVariableInstanceEntity)this.getDbSqlSession().findInCache(HistoricVariableInstanceEntity.class, variable.getId());
            if (historicProcessVariable == null) {
                historicProcessVariable = Context.getCommandContext().getHistoricVariableInstanceEntityManager().findHistoricVariableInstanceByVariableInstanceId(variable.getId());
            }

            if (historicProcessVariable != null) {
                historicProcessVariable.copyValue(variable);
            } else {
                HistoricVariableInstanceEntity.copyAndInsert(variable);
            }
        }

    }

submitFormProperties方法粗略分析到這兒了,最後:

processInstance.start();
return processInstance;

啓動:

public void start() {
        if (this.startingExecution == null && this.isProcessInstanceType()) {
            this.startingExecution = new StartingExecution(this.processDefinition.getInitial());
        }

        this.performOperation(AtomicOperation.PROCESS_START);
    }

performOperation源碼:

public void performOperation(AtomicOperation executionOperation) {
        if (executionOperation.isAsync(this)) {
            this.scheduleAtomicOperationAsync(executionOperation);
        } else {
            this.performOperationSync(executionOperation);
        }

    }

scheduleAtomicOperationAsync這個是異步job方法,看下performOperationSync源碼:

protected void performOperationSync(AtomicOperation executionOperation) {
        Context.getCommandContext().performOperation(executionOperation, this);
    }

繼續:

public void performOperation(AtomicOperation executionOperation, InterpretableExecution execution) {
        this.nextOperations.add(executionOperation);
        if (this.nextOperations.size() == 1) {
            try {
                Context.setExecutionContext(execution);

                while(!this.nextOperations.isEmpty()) {
                    AtomicOperation currentOperation = (AtomicOperation)this.nextOperations.removeFirst();
                    if (log.isTraceEnabled()) {
                        log.trace("AtomicOperation: {} on {}", currentOperation, this);
                    }

                    if (execution.getReplacedBy() == null) {
                        currentOperation.execute(execution);
                    } else {
                        currentOperation.execute(execution.getReplacedBy());
                    }
                }
            } finally {
                Context.removeExecutionContext();
            }
        }

currentOperation.execute(execution)源碼:

public void execute(InterpretableExecution execution) {
        ActivityImpl activity = (ActivityImpl)execution.getActivity();
        ActivityBehavior activityBehavior = activity.getActivityBehavior();
        if (activityBehavior == null) {
            throw new PvmException("no behavior specified in " + activity);
        } else {
            log.debug("{} executes {}: {}", new Object[]{execution, activity, activityBehavior.getClass().getName()});

            try {
                if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
                    Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createActivityEvent(ActivitiEventType.ACTIVITY_STARTED, execution.getActivity().getId(), (String)execution.getActivity().getProperty("name"), execution.getId(), execution.getProcessInstanceId(), execution.getProcessDefinitionId(), (String)activity.getProperties().get("type"), activity.getActivityBehavior().getClass().getCanonicalName()));
                }

                activityBehavior.execute(execution);
            } catch (RuntimeException var5) {
                throw var5;
            } catch (Exception var6) {
                LogMDC.putMDCExecution(execution);
                throw new PvmException("couldn't execute activity <" + activity.getProperty("type") + " id=\"" + activity.getId() + "\" ...>: " + var6.getMessage(), var6);
            }
        }
    }

這一步 activityBehavior.execute(execution);主要是Activiti設定的多種節點類型的執行行爲細節,這裏不做展開分析了,由於……實在太多了。

相關文章
相關標籤/搜索