博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Activiti启动流程源码解析
阅读量:6431 次
发布时间:2019-06-23

本文共 18855 字,大约阅读时间需要 62 分钟。

hot3.png

Activit启动流程主要有两种方式:

1、利用FormService启动:

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

2、利用RuntimeService启动:

public ProcessInstance startProcessInstanceById(String processDefinitionId, String businessKey, Map
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办理人数据变量就只能用后者启动了)。

此外,前者主要还是用于动态表单、外置表单类型的流程启动。后者用于普通表单类型的流程启动。两者本质区别是:前者会去解析表单字段,而后者不会,其他流程基本一致。 本篇将首先去解析formService.submitStartFormData启动流程的方法源码。

1、该启动方法共有两种重载形式:

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

区别仅在于是否需要传递businessKey参数(一般而言做实际业务时都是需要的),因此我们着重看第二种形式。

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

Activiti是一种典型的责任链+命令的设计模式,使得新手比较难于跟踪源码,建议有时间的话先去学习下这两种设计模式。 但是这种设计的好处也很明显,使得我们在对Activiti进行功能需求自定义或者扩展时显得异常方便。 好了,废话不多说,这里面具体的实现者是SubmitStartFormCmd这个命令类,跟进去看源码:

//// 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
{ private static final long serialVersionUID = 1L; protected final String businessKey; protected Map
properties; public SubmitStartFormCmd(String processDefinitionId, String businessKey, Map
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
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
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
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
properties, ExecutionEntity execution) { Map
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
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设定的多种节点类型的执行行为细节,这里不作展开分析了,因为……实在太多了。

转载于:https://my.oschina.net/u/180480/blog/2248984

你可能感兴趣的文章
springcloud eureka 服务注册中心
查看>>
SpringBoot 缓存&amp;资源优化
查看>>
【算法学习笔记】之分治算法
查看>>
蜗牛爬行日记——判断闰年
查看>>
classpath的作用
查看>>
Cimg代码初探
查看>>
推荐几种Java任务调度的实现
查看>>
如何用Docker定制你自己的Beego环境
查看>>
Design Pattern: Observer Pattern
查看>>
服务器性能配置要点总结
查看>>
.Net Core使用Redis的一个入门简单Demo
查看>>
汇洁集团牵手阿里云,开启内衣服饰企业数字化转型
查看>>
52. Python 爬虫(1)
查看>>
56. Python saltstack 二次开发(1)
查看>>
js实现分页的几个源码,看完基本就懂了
查看>>
算法学习之路|填方格(模拟)
查看>>
AGG第十六课 agg::path_storage 路径存储器
查看>>
Eclipse源代码分析
查看>>
CentOS6.5和CentOS7.0双网卡主备模式配置
查看>>
数据库数据类型
查看>>