flowable的部署有好幾種.現在舉例常用的方式:
Deployment deployment = repositoryService.createDeployment().name(bpmName).addInputStream(fileName, fileInputStream).deploy();
這裏分兩步先創建Deployment.然後再deploy.createDeployment()源碼如下:
@Override
public DeploymentBuilder createDeployment() {
return commandExecutor.execute(new Command<DeploymentBuilder>() {
@Override
public DeploymentBuilder execute(CommandContext commandContext) {
return new DeploymentBuilderImpl(RepositoryServiceImpl.this);
}
});
}
這裏是使用了建造者模式創建了一個DeploymentBuilder對象.
然後第二步是deploy.第一步中創建了一個DeploymentBuilder對象和RepositoryServiceImpl對象.部署就是通過給RepositoryServiceImpl對象注入DeploymentBuilder對象來實現的.代碼如下.
@Override
public Deployment deploy() {
return repositoryService.deploy(this);
}
實現方法如下
public Deployment deploy(DeploymentBuilderImpl deploymentBuilder) {
return commandExecutor.execute(new DeployCmd<Deployment>(deploymentBuilder));
}
可以看到又是命令模式,我們看一下DeployCmd命令:部署分四步
1.插入表act_re_deployment.
2.設置部署參數,有兩個isBpmn20XsdValidationEnabled和isProcessValidationEnabled都是true,都是校驗.
3.實際部署.EngineDeployer,其中實際處理部署邏輯的是BpmnDeployer.這裏會進入到第一個if內,找到舊的,設置爲1或者舊版本+1.並且插入流程定義表act_re_procdef 中.關鍵源碼如下.
if (deployment.isNew()) {
if (!deploymentSettings.containsKey(DeploymentSettings.IS_DERIVED_DEPLOYMENT)) {
Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapOfNewProcessDefinitionToPreviousVersion = getPreviousVersionsOfProcessDefinitions(parsedDeployment);
setProcessDefinitionVersionsAndIds(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
persistProcessDefinitionsAndAuthorizations(parsedDeployment);
updateTimersAndEvents(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
} else {
Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapOfNewProcessDefinitionToPreviousDerivedVersion =
getPreviousDerivedFromVersionsOfProcessDefinitions(parsedDeployment);
setDerivedProcessDefinitionVersionsAndIds(parsedDeployment, mapOfNewProcessDefinitionToPreviousDerivedVersion, deploymentSettings);
persistProcessDefinitionsAndAuthorizations(parsedDeployment);
}
} else {
makeProcessDefinitionsConsistentWithPersistedVersions(parsedDeployment);
}
4.發佈創建實體事件.至此部署完畢.整個部署的關鍵代碼如下:
org.flowable.engine.impl.cmd.DeployCmd#executeDeploy
// Save the data
CommandContextUtil.getDeploymentEntityManager(commandContext).insert(deployment);
if (processEngineConfiguration.getEventDispatcher().isEnabled()) {
processEngineConfiguration.getEventDispatcher().dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_CREATED, deployment));
}
// Deployment settings
Map<String, Object> deploymentSettings = new HashMap<>();
deploymentSettings.put(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED, deploymentBuilder.isBpmn20XsdValidationEnabled());
deploymentSettings.put(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED, deploymentBuilder.isProcessValidationEnabled());
// Actually deploy
processEngineConfiguration.getDeploymentManager().deploy(deployment, deploymentSettings);
if (deploymentBuilder.getProcessDefinitionsActivationDate() != null) {
scheduleProcessDefinitionActivation(commandContext, deployment);
}
if (processEngineConfiguration.getEventDispatcher().isEnabled()) {
processEngineConfiguration.getEventDispatcher().dispatchEvent(FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.ENTITY_INITIALIZED, deployment));
}
flowable啓動流程有兩種方式.最終都是執行了StartProcessInstanceCmd命令,我以流程key方式啓動來分析源碼,從啓動流程開始.
啓動流程方式:ByKey
processInstance = runtimeService.startProcessInstanceByKey(procDefKey, businessTable + ":" + businessId, vars);
這個方法內部如下
commandExecutor.execute(new StartProcessInstanceCmd<ProcessInstance>(processDefinitionKey, null, businessKey, variables));
我們看到這裏使用了設計模式-命令模式,執行了一個StartProcessInstanceCmd命令.org.flowable.engine.impl.interceptor.CommandInvoker#execute方法就是獲取Context.把command的結果賦值給context.
final CommandContext commandContext = Context.getCommandContext();
// Execute the command.
// This will produce operations that will be put on the agenda.
agenda.planOperation(new Runnable() {
@Override
public void run() {
commandContext.setResult(command.execute(commandContext));
}
});
我們再看一下StartProcessInstanceCmd內部.org.flowable.engine.impl.cmd.StartProcessInstanceCmd#execute方法做了兩件事
1.根據CommandContext獲取流程引擎配置實現類ProcessEngineConfigurationImpl
2.獲取流程定義
3.啓動流程實例
源碼如下:
@Override
public ProcessInstance execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
processInstanceHelper = processEngineConfiguration.getProcessInstanceHelper();
ProcessDefinition processDefinition = getProcessDefinition(processEngineConfiguration);
ProcessInstance processInstance = null;
if (hasStartFormData()) {
processInstance = handleProcessInstanceWithForm(commandContext, processDefinition, processEngineConfiguration);
} else {
processInstance = startProcessInstance(processDefinition);
}
return processInstance;
}
a.獲取流程引擎配置比較簡單,因爲啓動的時候引擎已經初始化過了.先獲取引擎配置
if (commandContext != null) {
return (ProcessEngineConfigurationImpl) commandContext.getEngineConfigurations().get(EngineConfigurationConstants.KEY_PROCESS_ENGINE_CONFIG);
}
EngineConfigurations有很多種,流程key啓動時只有三種.
String KEY_PROCESS_ENGINE_CONFIG = "cfg.processEngine";
String KEY_IDM_ENGINE_CONFIG = "cfg.idmEngine";
String KEY_FORM_ENGINE_CONFIG = "cfg.formEngine";
b.我們再看獲取流程定義,其實就是去數據庫找流程部署表的記錄.流程定義的時候會添加流程定義記錄到act_re_procdef表.那麼是流程引擎是怎麼找到表的呢?
這就需要一個流程引擎配置類ProcessEngineConfiguration,在它的實現類中,initEntityManagers()方法和initDataManagers()分別初始化了EntihtyManager和DataManager.ProcessEngineConfigurationImpl把初始化好的DataManager注入XXXXXEntityManagerImpl裏.DataManager的相當於mybatis的mapper類,定義了方法的接口.
看一下initEntityManagers()部分源碼,給XXXXXEntityManagerImpl注入初始化的DataManager
if (processDefinitionEntityManager == null) {
processDefinitionEntityManager = new ProcessDefinitionEntityManagerImpl(this, processDefinitionDataManager);
}
有了流程引擎的配置信息就能獲取到操作流程的數據庫配置
ProcessDefinitionEntityManager processDefinitionEntityManager = processEngineConfiguration.getProcessDefinitionEntityManager();
所有操作數據庫的接口都繼承了EntityManager<EntityImpl extends Entity>接口,而操作實際是使用了DataManager,ProcessEngineConfigurationImpl是流程引擎的初始化類,
processDefinitionDataManager.findLatestProcessDefinitionByKey(processDefinitionKey);
processDefinitionDataManager最總使用的是sqlsession查詢數據庫.
(ProcessDefinitionEntity) getDbSqlSession().selectOne("selectLatestProcessDefinitionByKey", processDefinitionKey);
c.接下來是啓動流程實例.上一步我們已經查詢到了流程定義.現在就是流程實例的創建.是通過ProcessInstanceHelper的
createAndStartProcessInstanceWithInitialFlowElement()方法創建的.
有關鍵幾個步驟:
1.創建流程實例(初始化,然後設置值),創建參與者信息act_ru_identitylink.發佈創建實體事件.
2.插入act_hi_procinst表
3.發佈創建實體事件和創建實體變量事件
4.創建第一個執行節點,插入到act_ru_execution表中.
5.更新運行時實例表ACT_RU_ACTINST
// Create the process instance
String initiatorVariableName = null;
if (initialFlowElement instanceof StartEvent) {
initiatorVariableName = ((StartEvent) initialFlowElement).getInitiator();
}
String tenantId = null;
if (overrideDefinitionTenantId != null) {
tenantId = overrideDefinitionTenantId;
} else {
tenantId = processDefinition.getTenantId();
}
ExecutionEntity processInstance = CommandContextUtil.getExecutionEntityManager(commandContext)
.createProcessInstanceExecution(processDefinition, predefinedProcessInstanceId, businessKey, tenantId,
initiatorVariableName, initialFlowElement.getId());
processInstance.setName(processInstanceName);
// Callbacks
if (callbackId != null) {
processInstance.setCallbackId(callbackId);
}
if (callbackType != null) {
processInstance.setCallbackType(callbackType);
}
CommandContextUtil.getHistoryManager(commandContext).recordProcessInstanceStart(processInstance);
boolean eventDispatcherEnabled = CommandContextUtil.getProcessEngineConfiguration().getEventDispatcher().isEnabled();
if (eventDispatcherEnabled) {
CommandContextUtil.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
FlowableEventBuilder.createEntityEvent(FlowableEngineEventType.PROCESS_CREATED, processInstance));
}
processInstance.setVariables(processDataObjects(process.getDataObjects()));
// Set the variables passed into the start command
if (variables != null) {
for (String varName : variables.keySet()) {
processInstance.setVariable(varName, variables.get(varName));
}
}
if (transientVariables != null) {
for (String varName : transientVariables.keySet()) {
processInstance.setTransientVariable(varName, transientVariables.get(varName));
}
}
// Fire events
if (eventDispatcherEnabled) {
CommandContextUtil.getProcessEngineConfiguration().getEventDispatcher()
.dispatchEvent(FlowableEventBuilder.createEntityWithVariablesEvent(FlowableEngineEventType.ENTITY_INITIALIZED, processInstance, variables, false));
}
// Create the first execution that will visit all the process definition elements
ExecutionEntity execution = CommandContextUtil.getExecutionEntityManager(commandContext).createChildExecution(processInstance);
execution.setCurrentFlowElement(initialFlowElement);
CommandContextUtil.getActivityInstanceEntityManager(commandContext).recordActivityStart(execution);
由於時間有限.最後這一步有點粗糙.下次會專門寫一個文章分析啓動時源碼.如有疑問歡迎留言