
Activiti 手动部署 BPMN 流程时,若仅生成 ge_bytearray 记录而缺失 re_procdef 中的流程定义,通常因部署名称重复导致 Activiti 跳过实际部署。本文详解如何正确使用 Java API 手动部署、避免冲突,并提供健壮的实现示例。
activiti 手动部署 bpmn 流程时,若仅生成 `ge_bytearray` 记录而缺失 `re_procdef` 中的流程定义,通常因部署名称重复导致 activiti 跳过实际部署。本文详解如何正确使用 java api 手动部署、避免冲突,并提供健壮的实现示例。
在 Spring Boot + Activiti 环境中,启用自动部署(如通过 spring.activiti.check-process-definitions=true)时,框架会为每个 BPMN 文件生成唯一部署并注册流程定义到 ACT_RE_PROCDEF 表;但切换至手动 Java 部署后,若未显式指定唯一部署名或复用已有名称,Activiti 将依据“部署名称+资源名”进行幂等校验——相同部署名下已存在的资源会被跳过,不触发流程解析与定义注册,从而导致 re_procdef 为空,仅留下原始 XML 存于 ge_bytearray。
根本原因在于:DeploymentBuilder.deploy() 默认使用空字符串或 null 作为部署名称,而 Activiti 的 RepositoryServiceImpl.deploy() 内部会调用 findDeploymentsByName() 进行查重。若此前存在同名部署(例如启动时自动部署残留、或多次执行未清理),本次部署将被静默忽略。
✅ 正确做法是:为每次部署指定唯一、可追溯的名称。推荐结合时间戳、版本号或随机标识:
String deploymentName = "manual-deployment-" + System.currentTimeMillis();
DeploymentBuilder builder = repositoryService.createDeployment()
.name(deploymentName) // ✅ 关键:必须显式设置唯一名称
.category("custom-processes");同时,务必确保 addBpmnModel() 的第一个参数为合法的 BPMN 文件名(不含路径和扩展名),且与 <process id="..."></process> 中的 ID 保持一致(非必需但强烈建议),否则可能引发后续启动异常。优化后的完整部署逻辑如下:
@Autowired
private RepositoryService repositoryService;
@Autowired
private ResourceLoader resourceLoader;
public void deployProcessesManually() {
BpmnXMLConverter converter = new BpmnXMLConverter();
String processPath = "classpath:/processes/";
try {
Resource dirResource = resourceLoader.getResource(processPath);
File processDir = dirResource.getFile();
if (!processDir.exists()) {
log.warn("Process directory not found: {}", processPath);
return;
}
String[] bpmnFiles = processDir.list((dir, name) -> name.toLowerCase().endsWith(".bpmn20.xml"));
if (bpmnFiles == null || bpmnFiles.length == 0) {
log.info("No BPMN files found in {}", processPath);
return;
}
// ✅ 使用唯一部署名(含时间戳+计数,避免瞬时重复)
String deploymentName = String.format("deploy-%s-%d",
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss")),
bpmnFiles.length);
DeploymentBuilder builder = repositoryService.createDeployment()
.name(deploymentName)
.category("business-processes");
for (String fileName : bpmnFiles) {
try (InputStream is = resourceLoader.getResource(processPath + fileName).getInputStream()) {
BpmnModel model = converter.convertToBpmnModel(
new InputStreamSource(is), true, false);
// 提取 process key 作为资源名(推荐:与 <process id="xxx"> 一致)
String processKey = fileName.substring(0, fileName.lastIndexOf(".bpmn20.xml"));
builder.addBpmnModel(processKey + ".bpmn20.xml", model);
log.debug("Added BPMN model: {}", processKey);
} catch (IOException e) {
log.error("Failed to load BPMN file: {}", fileName, e);
}
}
Deployment deployment = builder.deploy(); // ✅ 执行部署
log.info("Successfully deployed {} processes under deployment ID: {}",
bpmnFiles.length, deployment.getId());
} catch (Exception e) {
log.error("Manual deployment failed", e);
throw new RuntimeException("Failed to deploy BPMN processes manually", e);
}
}⚠️ 注意事项:
-
禁止复用部署名:生产环境应避免硬编码名称(如
"my-deployment"),推荐使用时间戳、Git commit hash 或应用版本号; -
清理旧部署(开发/测试阶段):若需反复调试,可先删除历史部署(慎用于生产):
repositoryService.createDeploymentQuery() .deploymentNameLike("manual-deployment-%") .list() .forEach(d -> repositoryService.deleteDeployment(d.getId(), true)); -
验证部署结果:部署后检查数据库:
-
ACT_GE_BYTEARRAY: 应有对应DEPLOYMENT_ID的RESOURCE类型记录(XML 内容); -
ACT_RE_PROCDEF: 应存在DEPLOYMENT_ID关联的多条流程定义(KEY_,VERSION_,TENANT_ID_等字段非空);
-
-
Spring Boot 配置兼容性:若仍保留
spring.activiti.*配置,请确保spring.activiti.check-process-definitions=false,避免自动部署与手动逻辑冲突。
总结:Activiti 手动部署的核心在于显式、唯一、可管理的部署命名策略。只要规避名称冲突,并确保 addBpmnModel() 输入合法,即可稳定生成可执行的流程定义,完全替代自动部署机制。
















