Flowable BPMN扩展实战:从自定义属性定义到运行时动态解析
1. 为什么需要自定义BPMN属性在真实业务场景中标准BPMN规范提供的属性往往无法满足复杂流程需求。比如我们团队最近遇到的几个典型case会签场景需要标记最少通过人数动态指派任务时需要携带候选人角色白名单紧急审批流程要控制超时自动通过阈值这些业务规则如果硬编码在Java委托类里每次修改都要重新部署流程。而通过自定义属性可以直接在流程设计器可视化配置真正实现业务规则与流程引擎解耦。实测下来这种方案比传统开发方式节省了60%以上的流程迭代时间。2. 属性定义从元数据到可视化配置2.1 解剖stencilset_bpmn.json这个配置文件相当于Flowable设计器的属性字典。我习惯用VS Code打开它因为JSON结构清晰可见。关键在propertyPackages这个数组每个元素代表一组属性集合。举个例子{ name: approval_rules_package, properties: [ { id: minApprovers, type: Integer, title: 最少审批人数, defaultValue: 1, description: 会签场景下需要的最小同意人数 }, { id: allowEmergencyPass, type: Boolean, title: 允许紧急跳过, value: false } ] }踩坑提醒type字段支持的类型有限我实测可用类型包括String默认BooleanIntegerFloatDateEnum需要额外配置enumValues2.2 绑定到具体节点定义好的属性包需要关联到BPMN元素。在UserTask的配置块里添加引用{ type: node, id: UserTask, propertyPackages: [ approval_rules_package, another_package ] }有个小技巧属性显示顺序取决于它们在数组中的位置。我通常把高频属性放在前面方便业务人员配置。3. 属性持久化让配置真正生效3.1 自定义JsonConverter实战这里有个大坑设计器里配的属性默认不会保存到BPMN XML必须通过扩展UserTaskJsonConverter实现双向转换。分享我的模板代码public class CustomTaskConverter extends UserTaskJsonConverter { Override protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, MapString, JsonNode shapeMap) { UserTask task (UserTask) super.convertJsonToElement(elementNode, modelNode, shapeMap); // 处理数字类型属性 Integer minApprovers getPropertyValueAsInteger(minApprovers, elementNode); if (minApprovers ! null) { task.addCustomProperty(createProperty(minApprovers, minApprovers.toString())); } // 处理布尔类型属性 Boolean allowEmergency getPropertyValueAsBoolean(allowEmergencyPass, elementNode); if (allowEmergency ! null) { task.addCustomProperty(createProperty(allowEmergencyPass, allowEmergency.toString())); } return task; } private CustomProperty createProperty(String name, String value) { CustomProperty prop new CustomProperty(); prop.setId(name); prop.setName(name); prop.setSimpleValue(value); return prop; } }3.2 注册自定义转换器在Spring配置类中添加初始化逻辑Bean public BpmnJsonConverterConfigurer customConverterConfigurer() { return converter - { converter.getConvertersToBpmnMap().put(UserTask, CustomTaskConverter.class); converter.getConvertersToJsonMap().put(UserTask.class, CustomTaskConverter.class); }; }部署后查看生成的BPMN XML应该能看到类似这样的扩展属性userTask idtask1 name主管审批 extensionElements flowable:minApprovers3/flowable:minApprovers flowable:allowEmergencyPasstrue/flowable:allowEmergencyPass /extensionElements /userTask4. 运行时动态解析属性4.1 从流程定义获取属性在任务监听器或Java委托中我常用这套组合拳获取属性public class ApprovalRulesDelegate implements JavaDelegate { Override public void execute(DelegateExecution execution) { BpmnModel model repositoryService.getBpmnModel(execution.getProcessDefinitionId()); FlowElement element model.getFlowElement(execution.getCurrentActivityId()); if (element instanceof UserTask) { UserTask task (UserTask) element; // 获取数字类型属性 Integer minApprovers getExtensionProperty(task, minApprovers, Integer.class); // 获取布尔类型属性 Boolean allowEmergency getExtensionProperty(task, allowEmergencyPass, Boolean.class); // 业务逻辑处理... } } private T T getExtensionProperty(UserTask task, String name, ClassT type) { ListExtensionElement elements task.getExtensionElements() .getOrDefault(name, Collections.emptyList()); if (!elements.isEmpty()) { String value elements.get(0).getElementText(); if (type Integer.class) return (T) Integer.valueOf(value); if (type Boolean.class) return (T) Boolean.valueOf(value); return (T) value; } return null; } }4.2 动态覆盖属性值更高级的玩法是在运行时修改属性。比如根据业务数据动态调整审批人数// 在流程启动时动态注入 ProcessInstance instance runtimeService.startProcessInstanceByKey( approvalProcess, variables, Collections.singletonMap(minApprovers, 5) // 覆盖设计器配置 );5. 生产环境最佳实践5.1 性能优化方案在大规模流程应用中频繁解析BPMN模型会成为性能瓶颈。我的解决方案是属性缓存Cacheable(cacheNames flowableProperties, key #processDefinitionId : #activityId) public MapString, Object getTaskProperties(String processDefinitionId, String activityId) { // 解析逻辑... }配合Spring Cache使用TPS提升超过70%。缓存失效策略建议流程定义变更时清空相关缓存设置合理的TTL如30分钟5.2 错误处理经验这些坑我亲自踩过类型转换异常XML里的true转Boolean时要做trim()空指针防护getExtensionElements()可能返回null版本兼容升级Flowable版本时要测试属性解析逻辑建议在工具类中封装安全的获取方法public static OptionalString getSafeExtensionValue(UserTask task, String key) { return Optional.ofNullable(task.getExtensionElements()) .map(ext - ext.get(key)) .filter(list - !list.isEmpty()) .map(list - list.get(0).getElementText()); }6. 扩展应用场景6.1 动态任务指派结合自定义属性实现灵活的任务分配userTask idtask1 flowable:candidateUsers${approvers} extensionElements flowable:approverRulesDEPARTMENT_LEADER,PROJECT_MANAGER/flowable:approverRules /extensionElements /userTask在监听器中动态解析String rules getExtensionProperty(task, approverRules, String.class); ListString candidates roleService.findUsersByRoles(rules.split(,)); taskService.setAssignee(taskId, candidates.get(0));6.2 条件路由增强扩展的网关条件表达式sequenceFlow idflow1 sourceRefgateway1 targetReftask1 extensionElements flowable:advancedCondition${amount 10000 urgency HIGH}/flowable:advancedCondition /extensionElements /sequenceFlow在自定义的条件评估器中解析String condition getExtensionProperty(flow, advancedCondition, String.class); Expression expression expressionManager.createExpression(condition); return (Boolean) expression.getValue(variables);
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2494420.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!