使用Camunda流程引擎開發,如何讀取流程圖中配制的參數及參數值?


在使用開源 Camunda 流程引擎框架做二次開發,有時候會在固定節點添加固定的參數及參數值,流程在流轉到此節點時,我們如何運用Camunda從中取出配制的參數呢?

圖片

 

下面首先介紹 Camunda 支持配制哪些參數:

  1. String

  2. Map

  3. List

  4. Script

  5. String or Expression

在Camunda中,除開1類型之外,其它四種都是以對象的方式保存在流程中(解析出來保存在 ACT_GE_BYTEARRAY 表中)。配制String類型的是在 Extensions ;其它4種是在  Input/Output

圖片

 

上面介紹了使用 Camunda Modeler 流程圖工具配制參數,下面來看下流程圖是如何取到這些值的。

 

圖片

 

讀取這些值的方法還是很簡單,只有一句代碼:

Map<String, Object> map = runtimeService.getVariables(task.getExecutionId());

讀取配制的值很簡單,那有沒有想過這些值是怎么取到的呢?

 

大膽猜想一下,就是在部署流程解析XML文件的時候,這些值就解析出來了,然后在保存在緩存中。

 

有了猜想,下面再來驗證我們的猜想。

 

圖片

圖片

protected DeploymentWithDefinitions doExecute(final CommandContext commandContext) {
  DeploymentManager deploymentManager = commandContext.getDeploymentManager();


  // load deployment handler
  ProcessEngine processEngine = commandContext.getProcessEngineConfiguration().getProcessEngine();
  deploymentHandler = commandContext.getProcessEngineConfiguration()
      .getDeploymentHandlerFactory()
      .buildDeploymentHandler(processEngine);


  Set<String> deploymentIds = getAllDeploymentIds(deploymentBuilder);
  if (!deploymentIds.isEmpty()) {
    String[] deploymentIdArray = deploymentIds.toArray(new String[deploymentIds.size()]);
    List<DeploymentEntity> deployments = deploymentManager.findDeploymentsByIds(deploymentIdArray);
    ensureDeploymentsWithIdsExists(deploymentIds, deployments);
  }


  checkCreateAndReadDeployments(commandContext, deploymentIds);


  // set deployment name if it should retrieved from an existing deployment
  String nameFromDeployment = deploymentBuilder.getNameFromDeployment();
  setDeploymentName(nameFromDeployment, deploymentBuilder, commandContext);


  // get resources to re-deploy
  List<ResourceEntity> resources = getResources(deploymentBuilder, commandContext);
  // .. and add them the builder
  addResources(resources, deploymentBuilder);


  Collection<String> resourceNames = deploymentBuilder.getResourceNames();
  if (resourceNames == null || resourceNames.isEmpty()) {
    throw new NotValidException("No deployment resources contained to deploy.");
  }


  // perform deployment   
  DeploymentWithDefinitions deployment = commandContext.runWithoutAuthorization(() -> {
    acquireExclusiveLock(commandContext);
    DeploymentEntity deploymentToRegister = initDeployment();
    Map<String, ResourceEntity> resourcesToDeploy =
        resolveResourcesToDeploy(commandContext, deploymentToRegister);
    Map<String, ResourceEntity> resourcesToIgnore = new HashMap<>(deploymentToRegister.getResources());
    resourcesToIgnore.keySet().removeAll(resourcesToDeploy.keySet());


    // save initial deployment resources before they are replaced with only the deployed ones
    CandidateDeployment candidateDeployment =
        CandidateDeploymentImpl.fromDeploymentEntity(deploymentToRegister);
    if (!resourcesToDeploy.isEmpty()) {
      LOG.debugCreatingNewDeployment();
      deploymentToRegister.setResources(resourcesToDeploy);
      deploy(commandContext, deploymentToRegister);
    } else {
      // if there are no resources to be deployed, find an existing deployment
      String duplicateDeploymentId =
          deploymentHandler.determineDuplicateDeployment(candidateDeployment);
      deploymentToRegister =
          commandContext.getDeploymentManager().findDeploymentById(duplicateDeploymentId);
    }


    scheduleProcessDefinitionActivation(commandContext, deploymentToRegister);


    if(deploymentBuilder instanceof ProcessApplicationDeploymentBuilder) {
      // for process application deployments, job executor registration
      // is managed by the ProcessApplicationManager
      ProcessApplicationRegistration registration = registerProcessApplication(
          commandContext,
          deploymentToRegister,
          candidateDeployment,
          resourcesToIgnore.values());


      return new ProcessApplicationDeploymentImpl(deploymentToRegister, registration);
    } else {
      registerWithJobExecutor(commandContext, deploymentToRegister);
    }


    return deploymentToRegister;
  });


  createUserOperationLog(deploymentBuilder, deployment, commandContext);


  return deployment;
}



、********************public <T> T runWithoutAuthorization(Callable<T> runnable) {
  CommandContext commandContext = Context.getCommandContext();
  boolean authorizationEnabled = commandContext.isAuthorizationCheckEnabled();
  try {
    commandContext.disableAuthorizationCheck();
    return runnable.call();
  } catch (RuntimeException e) {
    throw e;
  } catch (Exception e) {
    throw new ProcessEngineException(e);
  } finally {
    if (authorizationEnabled) {
      commandContext.enableAuthorizationCheck();
    }
  }
}

代碼調試發現,上面的代碼就是部署流程的核心代碼。

代碼一步一步跟蹤調試,終是沒有發現解析參數的地方?上面的猜想失敗了

那Camunda 到底是如何處理參數的呢?調試了好幾天,都沒有發現解析參數的地方!真的都被搞的很點失去信心了。

就在3月17日下午,我重新整理了調整了思路。

是不是直接從表里面查詢出來的?

試試跟蹤 runtimeService.getVariables(task.getExecutionId()) 這個方法,終於發現了一點眉目,真是從表查詢出來的。

public VariableMap execute(CommandContext commandContext) {
  ensureNotNull("executionId", executionId);

  ExecutionEntity execution = commandContext
    .getExecutionManager()
    .findExecutionById(executionId);

  ensureNotNull("execution " + executionId + " doesn't exist", "execution", execution);

  checkGetExecutionVariables(execution, commandContext);

  VariableMapImpl executionVariables = new VariableMapImpl();

  // collect variables from execution  核心方法
  execution.collectVariables(executionVariables, variableNames, isLocal, deserializeValues);

  return executionVariables;
}

 

// selectVariablesByExecutionId 對應執行的SQL語句
SELECT RES.*,
       ( case when RES.TASK_ID_ is not null and RES.EXECUTION_ID_ is not null then EXECUTION.ACT_INST_ID_
           when RES.CASE_EXECUTION_ID_ is not null then RES.CASE_EXECUTION_ID_ when EXECUTION.PARENT_ID_ is null
          and RES.IS_CONCURRENT_LOCAL_ = 0 then EXECUTION.ID_ when EXECUTION.IS_SCOPE_ = 1 and EXECUTION.PARENT_ID_ is not null
          and RES.IS_CONCURRENT_LOCAL_ = 0 then PARENT_EXECUTION.ACT_INST_ID_ else EXECUTION.ACT_INST_ID_ end ) ACT_INST_ID_
FROM ACT_RU_VARIABLE RES LEFT JOIN ACT_RU_EXECUTION EXECUTION ON RES.EXECUTION_ID_ = EXECUTION.ID_
    LEFT JOIN ACT_RU_EXECUTION PARENT_EXECUTION ON EXECUTION.PARENT_ID_ = PARENT_EXECUTION.ID_
WHERE EXECUTION_ID_ = '54854e59-a5c7-11ec-a5f8-92b1d713a145' AND TASK_ID_ is null

 

執行上面的SQL后,會返回  List< VariableInstanceEntity > 列表對象,在 VariableInstanceEntity 對象中有  ByteArrayField 屬性,它保證的是 一條 ACT_GE_BYTEARRAY(保存的對象信息,也就是需要序列化的參數) 表的數據信息。
 
總結 runtimeService.getVariables 執行過程:
    1、根據當前任務ID獲取當 executionId,根據 executionId 查詢 ACT_RU_VARIABLE 參數表
    2、判斷 ACT_RU_EXECUTION 表中的 PARENT_ID_  是否有值,有值就繼續根據此值查詢 ACT_RU_VARIABLE
    3、 根據查詢的  ACT_RU_VARIABLE 結果中 BYTEARRAY_ID_ 有值,就根據此ID去查詢ACT_GE_BYTEARRAY 資源信息表,反序列化對象


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM