flowable部署和启动源码解析

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);

由于时间有限.最后这一步有点粗糙.下次会专门写一个文章分析启动时源码.如有疑问欢迎留言

 

 


 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞翔的咩咩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值