Appearance
设计原理 08 · 引擎元数据——值漂移问题与注册式决策
对应规范:07 · 元数据能力
1. 要解决的问题:只有引擎自己知道的数据
前端流程设计器(vben5-wf)的配置项依赖两类数据,它们只存在于引擎内部:
- SPI 实现清单:可用的 AssignmentHandler / CandidateHandler / FlowInterceptor—— 设计器的下拉框要列出"有哪些处理器可选",value 是运行时引擎用来加载的类名/handlerName;
- 内置状态枚举:流程定义/实例/任务状态、提交类型——设计器和列表页要渲染 code → label。
在 boot3 时代,这些由 mldong 框架的"枚举注解 + classpath 扫描器 + 数据库字典"提供。 jeeflow 引擎核心零框架依赖(不能打 mldong 注解),于是每个集成方都要自己重复实现: 自己写扫描器、自己重新定义枚举。多语言联邦下,这个问题逐语言放大(四份重复实现), 且每次引擎加一个状态/处理器,集成方不知道 → 值漂移(枚举值、字典 label 与引擎不一致)。
2. 决策一:枚举字典直接由引擎枚举生成
为什么不用"集成方自行定义枚举"
集成方定义枚举 = 拷贝一份值表。引擎加状态(如 v1.4.0 给 InstanceState 补 WITHDRAW/INTERRUPT/PENDING/ABANDON)时,集成方不更新 → 字典缺项、前端渲染错。 事实已经发生:Go/Python/Node 的 InstanceState 在 v1.4.0 前只有 3 个值,且命名与 Java 不同(DONE vs FINISHED)。
设计
text
EnumDictRegistry.getDict("wf_process_instance_state")
→ [{value:"10", label:"进行中"}, ...] // 直接来自枚举的 code/message- key 约定 = boot3 字典 key(
wf_+ 枚举名转下划线):存量前端零改动, 集成方的 CustomDictService 只做"key 透传"; - 枚举新增/变更自动反映到字典——值漂移在源头消除;
- 枚举本身已有 code/message(v1.0 就设计好的),注册表只是"把它们摆出来",零额外声明。
多语言形态
- Java:枚举统一实现
IDictEnum(getCode/getMessage),注册表泛型生成; - Go/Python/Node:没有 Java 式枚举,v1.4.0 补齐完整枚举 + 显式字典表 (value/label 与 Java 逐项对齐,测试锁定)。
3. 决策二:SPI 清单走"注册式",不用接口默认方法/注解
issue 提议过两种元数据形态:
- 方式 A:接口默认方法(
default String getMessage())——Java 可行, 但 Go 接口没有默认方法、Python ABC 默认方法语义不同、Node interface 没有——多语言无法对齐; - 方式 B:注解(
@HandlerMeta)——Java 可行,但 Go/Python/Node 没有注解概念。
为什么选"注册式"(HandlerRegistry)
关键洞察:引擎是懒加载的,不是注册中心——Java 按类名 Class.forName, Go/Python/Node 靠扩展点函数按 handlerName 分发。引擎自己也不知道"有哪些可用实现", 这些实现属于集成方的选择(每个集成方可用处理器集合不同)。
注册式 = 集成方在启动时把"自己可用的实现 + 元数据"登记进 HandlerRegistry:
text
集成方扫描器(Spring Bean 扫描 / 手动装配)
→ register(type, className/handlerName, displayName, order, group)
→ listHandlers(type) 生成设计器下拉字典- 字典与运行时天然一致:字典的 value 就是节点配置里写的同一个字符串;
- 零侵入:现有处理器接口和实现零改动,不注册不影响引擎加载行为;
- 多语言对齐:每个语言一个 Map 注册表,Node 直接扩展既有
HandlerRegistry(引擎本来就用它做名称解析),Java/Go/Python 新增独立类/模块。
4. 为什么这能终结"扫描器重复"
boot4 此前有 4 个扫描器(assignment/candidate/pre/post)各自扫 classpath 生成字典。 重构后:扫描结果 → 注册 → 字典来自注册表,4 个扫描器塌缩为 1 个 CustomDictService 薄映射;多语言联邦下,各语言集成方共享同一套注册 API 心智模型,不再各自发明。