使用Camunda流程引擎开发,如何读取流程图中配制的参数及参数值?

momory

共 6412字,需浏览 13分钟

 · 2022-04-01

在使用开源 Camunda 流程引擎框架做二次开发,有时候会在固定节点添加固定的参数及参数值,流程在流转到此节点时,我们如何运用Camunda从中取出配制的参数呢?

f70ea4d59a0e603ba2cb85b1c52e9113.webp


下面首先介绍 Camunda 支持配制哪些参数:

  1. String

  2. Map

  3. List

  4. Script

  5. String or Expression

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

c609f18ff6978a1bfb16b2f3733edfc2.webp


上面介绍了使用 Camunda Modeler 流程图工具配制参数,下面来看下流程图是如何取到这些值的。


4953ff476aa79b3f0ae364f1a47950e9.webp


读取这些值的方法还是很简单,只有一句代码:

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

读取配制的值很简单,那有没有想过这些值是怎么取到的呢?


大胆猜想一下,就是在部署流程解析XML文件的时候,这些值就解析出来了,然后在保存在缓存中。


有了猜想,下面再来验证我们的猜想。


1999e62e5c16540ceee1c2166db51710.webp

1a731bb035f3226e6059aec9494bfc54.webp

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 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 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 runWithoutAuthorization(Callable 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;}

    d7090c843f28cd0ff90e0291e5750106.webp

82c4a8c31e23cd336ed5afc8802db724.webp

8e41bcdbfde80b2a6d8dfbc2c52bd2ea.webp


// 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 资源信息表,反序列化对象


   

浏览 136
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报