简述:
目前通过源码得知camunda流程引擎,在系统启动时,会根据bpmn文件部署流程,所以我们来看下整个bpmn文件是如何加载存储并使用的。
源码入口
SpringProcessEngineConfiguration
@Override
public ProcessEngine buildProcessEngine() {
ProcessEngine processEngine = super.buildProcessEngine();
//自动部署
autoDeployResources(processEngine);
return processEngine;
}
autoDeployResources会通过RepositoryServiceImpl.deploy方法执行部署。内部利用了命令模式。最终调用DeployCmd.doExecute(CommandContext commandContext)
下面我们介绍下这个方法的执行逻辑。
//解析源信息待部署
Map resourcesToDeploy = resolveResourcesToDeploy(commandContext, deployment);
resolveResourcesToDeploy方法主体分两步
step1:读取库中存有的最近一个部署版本和部署版本对应的流程图
库为:ACT_GE_BYTEARRAY 和 ACT_RE_DEPLOYMENT
Map existingResources = commandContext
.getResourceManager()
.findLatestResourcesByDeploymentName(deployment.getName(), containedResources.keySet(), source, deployment.getTenantId());
对应的mybatis sql 为
select B.*
from ${prefix}ACT_GE_BYTEARRAY B
inner join
(select B.NAME_, MAX(D.DEPLOY_TIME_) DEPLOY_TIME_
from ${prefix}ACT_GE_BYTEARRAY B
inner join ${prefix}ACT_RE_DEPLOYMENT D
on B.DEPLOYMENT_ID_ = D.ID_
where D.NAME_ = #{parameter.deploymentName}
and
(D.SOURCE_ is null or
D.SOURCE_ = #{parameter.source}
)
and B.NAME_ in
#{resourceName}
group by B.NAME_) LAST_RESOURCE
on B.NAME_ = LAST_RESOURCE.NAME_
inner join ${prefix}ACT_RE_DEPLOYMENT D
on B.DEPLOYMENT_ID_ = D.ID_
and D.DEPLOY_TIME_ = LAST_RESOURCE.DEPLOY_TIME_
and D.NAME_ = #{parameter.deploymentName}
and
(D.SOURCE_ is null or
D.SOURCE_ = #{parameter.source}
)
and D.TENANT_ID_ = #{ parameter.tenantId }
and D.TENANT_ID_ is null
step2:比较传入的流程图版本是否和库中的一致,如果不一致则使用当前resource中读取到的流程图
if (existingResource == null
|| existingResource.isGenerated()
|| resourcesDiffer(deployedResource, existingResource))
resourcesDiffer方法
protected boolean resourcesDiffer(ResourceEntity resource, ResourceEntity existing) {
byte[] bytes = resource.getBytes();
byte[] savedBytes = existing.getBytes();
return !Arrays.equals(bytes, savedBytes);
}
拿到需要部署的流程图后,如果resourcesToDeploy不为空,那么需要将最新版本的流程落库存储并存入缓存DeploymentCache。
if (!resourcesToDeploy.isEmpty()) {
//落库并部署
LOG.debugCreatingNewDeployment();
deployment.setResources(resourcesToDeploy);
deploy(deployment);
} else {
LOG.usingExistingDeployment();
deployment = getExistingDeployment(commandContext, deployment.getName());
}
protected void deploy(DeploymentEntity deployment) {
deployment.setNew(true);
Context
.getCommandContext()
.getDeploymentManager()
.insertDeployment(deployment);
}
public void insertDeployment(DeploymentEntity deployment) {
getDbEntityManager().insert(deployment);
createDefaultAuthorizations(deployment);
for (ResourceEntity resource : deployment.getResources().values()) {
resource.setDeploymentId(deployment.getId());
getResourceManager().insertResource(resource);
}
Context
.getProcessEngineConfiguration()
.getDeploymentCache()
.deploy(deployment);
}
接着执行的是deploy方法实际执行的是子类BpmnDeployer.transformDefinitions 进行数据解析
protected List transformDefinitions(DeploymentEntity deployment, ResourceEntity resource, Properties properties) {
byte[] bytes = resource.getBytes();
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
BpmnParse bpmnParse = bpmnParser
.createParse()
.sourceInputStream(inputStream)
.deployment(deployment)
.name(resource.getName());
if (!deployment.isValidatingSchema()) {
bpmnParse.setSchemaResource(null);
}
bpmnParse.execute();
if (!properties.contains(JOB_DECLARATIONS_PROPERTY)) {
properties.set(JOB_DECLARATIONS_PROPERTY, new HashMap>>());
}
properties.get(JOB_DECLARATIONS_PROPERTY).putAll(bpmnParse.getJobDeclarations());
return bpmnParse.getProcessDefinitions();
}
最终会走到
protected void parseRootElement() {
collectElementIds();
parseDefinitionsAttributes();
parseImports();
parseMessages();
parseSignals();
parseErrors();
parseEscalations();
parseProcessDefinitions();
parseCollaboration();
// Diagram interchange parsing must be after parseProcessDefinitions,
// since it depends and sets values on existing process definition objects
parseDiagramInterchangeElements();
for (BpmnParseListener parseListener : parseListeners) {
parseListener.parseRootElement(rootElement, getProcessDefinitions());
}
}