技术交流28群

服务热线

135-6963-3175

微信服务号

activti之bpmn部署器BpmnDeployer源码解析 更新时间 2022-3-19 浏览2012次

流程的部署主要通过DeployCmd类进行:

查看部分核心代码:

public Deployment execute(CommandContext commandContext) {
    // Backwards compatibility with Activiti v5
    //activiti5兼容开启
    if (commandContext.getProcessEngineConfiguration().isActiviti5CompatibilityEnabled()
        && deploymentBuilder.getDeploymentProperties() != null 
        && deploymentBuilder.getDeploymentProperties().containsKey(DeploymentProperties.DEPLOY_AS_ACTIVITI5_PROCESS_DEFINITION)
        && deploymentBuilder.getDeploymentProperties().get(DeploymentProperties.DEPLOY_AS_ACTIVITI5_PROCESS_DEFINITION).equals(Boolean.TRUE)) {
      
        return deployAsActiviti5ProcessDefinition(commandContext);
    }
    //执行部署
    return executeDeploy(commandContext);
  }
  protected Deployment executeDeploy(CommandContext commandContext) {
    //获取刚构建的部署对象
    DeploymentEntity deployment = deploymentBuilder.getDeployment();
    //设置部署当前时间
    deployment.setDeploymentTime(commandContext.getProcessEngineConfiguration().getClock().getCurrentTime());
    //在部署时会检测已部署的相同文件的最后一条记录,如果内容相同,则不会部署
    if (deploymentBuilder.isDuplicateFilterEnabled()) {
      //保存查到的集合
      List<Deployment> existingDeployments = new ArrayList<Deployment>();
      if (deployment.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(deployment.getTenantId())) {//TenantId不存在,通过部署名称查询数据库
        //查ACT_RE_DEPLOYMENT该表
        DeploymentEntity existingDeployment = commandContext.getDeploymentEntityManager().findLatestDeploymentByName(deployment.getName());
        if (existingDeployment != null) {
          existingDeployments.add(existingDeployment);
        }
      } else {//TenantId存在
        List<Deployment> deploymentList = commandContext.getProcessEngineConfiguration().getRepositoryService().createDeploymentQuery().deploymentName(deployment.getName())
            .deploymentTenantId(deployment.getTenantId()).orderByDeploymentId().desc().list();
        if (!deploymentList.isEmpty()) {
          existingDeployments.addAll(deploymentList);
        }
      }
      DeploymentEntity existingDeployment = null;
      if (!existingDeployments.isEmpty()) {
        existingDeployment = (DeploymentEntity) existingDeployments.get(0);
      }
      //查到且和要部署的一致,则直接返回查出来的
      if ((existingDeployment != null) && !deploymentsDiffer(deployment, existingDeployment)) {
        return existingDeployment;
      }
    }
    deployment.setNew(true);//设置为一个新的定义
    // Save the data
    //插入ACT_RE_DEPLOYMENT表(1条)和ACT_GE_BYTEARRAY表(png和bpmn定义)
    commandContext.getDeploymentEntityManager().insert(deployment);
    if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {//默认开启
      //触发deployment entity被创建的事件(默认不执行任何操作,只是日志的输出等)
      commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, deployment));
    }
    // Deployment settings
    Map<String, Object> deploymentSettings = new HashMap<String, Object>();
    //bpmn2.0检查,默认开启
    deploymentSettings.put(DeploymentSettings.IS_BPMN20_XSD_VALIDATION_ENABLED, deploymentBuilder.isBpmn20XsdValidationEnabled());
    //process流程定义检查,默认开启
    deploymentSettings.put(DeploymentSettings.IS_PROCESS_VALIDATION_ENABLED, deploymentBuilder.isProcessValidationEnabled());
    // Actually deploy
    //执行真正的部署操作
    commandContext.getProcessEngineConfiguration().getDeploymentManager().deploy(deployment, deploymentSettings);
    if (deploymentBuilder.getProcessDefinitionsActivationDate() != null) {//流程定义是否有激活日期
      scheduleProcessDefinitionActivation(commandContext, deployment);//进行流程定义的挂起或定时激活
    }
    if (commandContext.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {//默认开启
      //触发entity被初始化事件
      commandContext.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED, deployment));
    }
    return deployment;
  }

主要做的操作:

1、获取部署对象设置部署时间

2、在部署时会检测已部署的相同文件的最后一条记录,如果内容相同,则不会部署

     查到且和要部署的一致,则直接返回查出来的

    否则:

      2.1 设置为一个新的定义

      2.2 插入ACT_RE_DEPLOYMENT表(1条)和ACT_GE_BYTEARRAY表(png和bpmn定义)

      2.3设置bpmn2.0检查开启,process流程定义检查开启

3、执行真正的部署

4、流程定义是否有激活日期,有则进行流程定义的挂起或定时激活


分析部署代码

commandContext.getProcessEngineConfiguration().getDeploymentManager().deploy(deployment, deploymentSettings);

在deploymentManager里调用了BpmnDeployer的deploy方法。查看BpmnDeployer的deploy方法://真正的流程部署

@Override
  public void deploy(DeploymentEntity deployment, Map<String, Object> deploymentSettings) {
    log.debug("Processing deployment {}", deployment.getName());
    // The ParsedDeployment represents the deployment, the process definitions, and the BPMN 
    // resource, parse, and model associated with each process definition.
    ParsedDeployment parsedDeployment = parsedDeploymentBuilderFactory
        .getBuilderForDeploymentAndSettings(deployment, deploymentSettings)
        .build();
    //校验文件里的多个流程定义不能出现多个同样的key
    bpmnDeploymentHelper.verifyProcessDefinitionsDoNotShareKeys(parsedDeployment.getAllProcessDefinitions());
    //通过deployment为流程定义赋更多属性(引擎版本、tenantId、deploymentId)
    bpmnDeploymentHelper.copyDeploymentValuesToProcessDefinitions(
        parsedDeployment.getDeployment(), parsedDeployment.getAllProcessDefinitions());
    //为流程定义设置资源名称
    bpmnDeploymentHelper.setResourceNamesOnProcessDefinitions(parsedDeployment);
    //判断是否需要生成图片
    createAndPersistNewDiagramsIfNeeded(parsedDeployment);
    //为定义设置图片资源名称
    setProcessDefinitionDiagramNames(parsedDeployment);
    
    if (deployment.isNew()) {//新的
      //查是否存在老的并放入map返回(new:old)
      Map<ProcessDefinitionEntity, ProcessDefinitionEntity> mapOfNewProcessDefinitionToPreviousVersion =
          getPreviousVersionsOfProcessDefinitions(parsedDeployment);
      //给流程定义初始化流程定义id,设置版本号为1或者(根据是否有旧的版本号+1)
      setProcessDefinitionVersionsAndIds(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
      //流程定义入库,并给流程定义设置候选人也入库
      persistProcessDefinitionsAndAuthorizations(parsedDeployment);
      //取消旧的消息、信号、定时启动事件等及删库,且入库新的并绑定对应事件
      updateTimersAndEvents(parsedDeployment, mapOfNewProcessDefinitionToPreviousVersion);
      dispatchProcessDefinitionEntityInitializedEvent(parsedDeployment);//触发流程定义被初始化事件
    } else {
      //不是新的,则查出来的旧的,并给当前定义设置相关属性(貌似可用于更新(因为版本号没有增加))
      makeProcessDefinitionsConsistentWithPersistedVersions(parsedDeployment);
    }
    //缓存操作:流程定义放入全局流程定义缓存map和全局流程定义treeNode缓存map,
    //还有一个deployedArtifacts部署记录map(class org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl:实例list)
    cachingAndArtifactsManager.updateCachingAndArtifacts(parsedDeployment);
    
    for (ProcessDefinitionEntity processDefinition : parsedDeployment.getAllProcessDefinitions()) {
      BpmnModel bpmnModel = parsedDeployment.getBpmnModelForProcessDefinition(processDefinition);
      //更新流程定义中国际化数据
      createLocalizationValues(processDefinition.getId(), bpmnModel.getProcessById(processDefinition.getKey()));
    }
  }

可以看出主要执行的操作:

1、进行了bpmn xml的解析和构建并保存在ParsedDeployment对象里:

该类相关数据结构:

  protected DeploymentEntity deploymentEntity;
  protected List<ProcessDefinitionEntity> processDefinitions;
  protected Map<ProcessDefinitionEntity, BpmnParse> mapProcessDefinitionsToParses;
  protected Map<ProcessDefinitionEntity, ResourceEntity> mapProcessDefinitionsToResources;

2、校验文件里的多个流程定义不能出现多个同样的key

3、通过deployment为流程定义赋更多属性(引擎版本、tenantId、deploymentId)

4、为流程定义设置资源名称

5、判断是否需要生成图片,不存在则创建diagram(入库ACT_GE_BYTEARRAY)

6、为定义设置图片资源名称

7、isNew是否为创建新的:

    是:

        7.1 查是否存在老的定义并放入map返回(new:old)

        7.2 给流程定义初始化流程定义id,设置版本号为1或者(根据是否有旧的版本号+1)

        7.3 流程定义入库,并给流程定义设置候选人也入库(流程定义入库ACT_RE_PROCDEF表;

          流程启动候选人组入库ACT_RU_IDENTITYLINK:

                    getCandidateStarterUsers\getCandidateStarterGroups)

        7.4 取消旧的消息、信号、定时启动事件等及删库,且入库新的并绑定对应事件

                                                        (ACT_RU_EVENT_SUBSCR,ACT_RU_TIMER_JOB)

        7.5 触发流程定义被初始化事件

    否:

        7.1 不是新的,则查出来的旧的,并给当前定义设置相关属性(貌似可用于更新(因为版本号没有增加))

8、缓存操作:流程定义放入全局流程定义缓存map和全局流程定义treeNode缓存map,
    //还有一个deployedArtifacts部署记录map(class org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl:实例list)

    DeploymentCache<ProcessDefinitionCacheEntry>
    ProcessDefinitionInfoCache
    Map<Class<?>, List<Object>> deployedArtifacts;

9、更新所有流程定义中的国际化数据

相关说明:

//查找localization下语言为es的下id为id下属性为name
//例如结构{"localization":{"es":{"id1":{"name":"123"}}}} 返回"123"
JsonNode localizationNode = infoNode.path("localization").path(language).path(id).path(propertyName);

上面国际化数据通过查询ACT_PROCDEF_INFO表