不改内核也能挂业务:工作流引擎的三层挂接模型

不改内核也能挂业务:工作流引擎的三层挂接模型

一句话:评估流程引擎,别只看「能不能画流程」;更要看——业务逻辑能不能在不污染内核的前提下,挂到固定生命周期点上。
本文口径:把这种能力抽象为L1 交互层 / L2 服务层 / L3 配置编排层,再用同一把尺子对照 Java 与 .NET 两侧常见开源产品。
写作原则:名词可以不同,诉求相同;有优势写优势,有短板写短板;不以某一厂商叙事替代行业共性。


1. 先把「二开」说清楚

1.1 什么叫流程引擎的二开

流程引擎二开= 流程(模板)设计完成之后,在不修改引擎内核发送 / 流转代码的前提下,用脚本、类、配置或 Worker,与引擎在固定生命周期点交互,从而完成业务校验、集成、通知、台账等逻辑的过程。

对比项改引擎源码流程二开(本文范围)
改动位置发送 / 退回 / 调度内核外挂、事件、自定义 Activity、配置执行体
升级成本高,难合并相对低,核心可独立升级
职责边界引擎与业务缠在一起引擎管流转,二开管业务
可交付性难复用、难交接可按流程模板 / 模块绑定交付

典型动作:发送前校验、发送后同步第三方、退回拦截、流程结束写台账、自定义活动节点、自定义办理页按钮等。

1.2 为什么产品名词各异,却是同一件事

各产品对「挂业务」的叫法并不统一:Listener、Delegate、Action、StepBody、Custom Activity、外挂、事件配置、ServiceTask……
评估时不必纠结名词,应看三件事是否成立:

  1. 有没有稳定的生命周期时钟(发送前 / 发送后 / 完成 / 退回 / 结束……)
  2. 业务代码是否落在内核之外(可独立升级、可按模板绑定)
  3. 前端、后端、配置是否都能接到同一套语义(或至少有清晰分层)

这三件事,正是下文「三层挂接模型」要回答的。


2. 三层挂接模型:L1 / L2 / L3

把二开能力按「谁写、写在哪、管什么边界」拆成三层:

层级名称一句话谁写典型载体擅长不适合单独承担
L1交互层前端 / 页面侧写脚本交互前端 / 全栈办理页钩子、表单脚本、设计器 UI 插件发送前校验、按钮定制、提示、字段联动强事务写库、跨系统强一致
L2服务层后端 / 进程内写代码后端JavaDelegate、Listener、FlowEvent、StepBody、自定义 Activity强事务、改接收人 / 跳转、同步 ERP、审计纯 UI 即时反馈
L3配置 / 编排层设计器或模型配置实施 / 低代码SQL / HTTP / 脚本 / 表达式 / CodeAction少写代码也能挂业务复杂分支、深度引擎变量重构

运行时可以理解为同一条业务动作的分层叠加(示意):

用户点击「发送」 ├─ L1 交互层:页面校验 / 拦截 / 按钮与提示 └─ 请求进入引擎 ├─ L2 服务层:进程内代码(可改路由、写库、调系统) └─ L3 配置层:SQL / HTTP / 脚本 / 表达式(实施可配)

关键认识:三层不是互斥三选一,而是允许叠加。常见顺序是 L1 先拦人机边界 → L2 再守系统真相 → L3 承接标准化连接。

2.1 这一能力的作用

  1. 把「流转」和「业务」拆开:引擎回答怎么走,二开回答走到某点时业务做什么。
  2. 把交付从「改核」变成「挂点」:项目差异落在外挂与配置,而不是 fork 一份引擎。
  3. 让不同角色都能参与:前端、后端、实施不必挤在同一条技术路径上。
  4. 让升级成为可能:内核独立演进,业务扩展可保留、可迁移、可按模板复用。

2.2 为什么它是重要评估指标

选型时如果只看「有没有设计器 / 是否 BPMN」,很容易漏掉真正决定项目成败的问题:

若二开能力弱项目侧常见后果
只能改源码挂业务升级噩梦、合并冲突、人员不敢动引擎
只有后端代码扩展前端交互与实施配置缺位,交付慢、协作成本高
只有配置没有代码出口复杂规则被迫塞进脚本地狱,难测难重构
事件时钟不产品化团队靠猜「什么时候会触发」,集成不可控

因此:二开不是售后补丁,而是引擎产品能力的一等公民。
尤其在政企审批、ERP 集成、多系统待办同步等场景,L1/L2/L3 是否齐全,往往比「画布好不好看」更能决定能不能按期上线、能不能长期维护。


3. 三层分别解决什么问题

3.1 L1 交互层:人还在页面上时

问题:发送前要不要先提示?字段要不要联动?按钮要不要定制?成功后要不要局部刷新?

价值:反馈即时,减少无效请求;把「人机交互边界」拦在浏览器侧。
边界:页面可拦截,但业务真相以服务端为准——金额、库存、权限最终仍应在 L2/L3 再校验一遍。

常见形态:

  • 办理页 / 表单脚本(发送前、打开后、字段变更)
  • 前端外挂类 / Override 钩子
  • 设计器 UI 扩展(工具栏、表单控件、画布元素)

3.2 L2 服务层:进入引擎事务边界之后

问题:要不要改下一节点接收人?要不要同步 ERP?要不要写审计台账?要不要在同一事务里失败回滚?

价值:强类型、可调试、可测试;能访问运行时上下文(当前节点、实例 ID、变量、发送结果等)。
边界:适合系统集成与规则编排;不适合用它替代页面即时交互。

常见形态:

  • Java:JavaDelegateExecutionListenerTaskListener
  • .NET:StepBody、Custom Activity、Action Provider、流程事件基类
  • 全局拦截 / 中间件(平台级策略)+ 流程级绑定(模板级策略)

3.3 L3 配置 / 编排层:少写代码也能挂

问题:没有专职开发时,实施能否在设计器里把「一条 SQL / 一个 HTTP / 一段表达式」挂上?

价值:把简单集成从程序员日程里解放出来;缩短交付周期。
边界:擅长标准化连接;复杂分支、深度重构仍应回到 L2。

常见形态:

  • BPMN 扩展:Listener / ServiceTask 上挂 class / expression / script
  • 设计器事件:SQL、WebApi、存储过程、业务单元
  • 方案内 CodeAction、表达式语言(JUEL / FEEL / 自有 DSL)

4. 流行引擎怎么实现:Java 阵营

资料依据为各产品公开文档与社区常见做法。评级是「机制完整度」,不是业务场景总分。
= 产品级、文档/样例完整;= 能做但需自建较多;= 基本不覆盖或需从零实现。

4.1 总对照(Java)

产品定位倾向L1 交互层L2 服务层L3 配置编排二开主叙事
Camunda(社区版 / 平台)BPMN 标准向编排 + 运维中(表单/办理页多自建或另接;Cockpit/Tasklist 可扩展但非审批门户一站式)(JavaDelegate、Execution/Task Listener、外部任务)(脚本、表达式、Listener 配置、Connector 生态)Listener + Delegate + External Task
FlowableBPMN / CMMN 引擎族中(UI 多自建;企业版能力更完整)(Delegate、Listener、解析期注入 Listener)(expression / script / class 挂接)与 Camunda 同源思想,Delegate Code 体系
Activiti经典 BPMN 引擎中偏弱(产品 UI 依赖版本与生态)(JavaDelegate、Listener)强偏中(脚本/表达式可用,实施配置体验因发行版而异)经典委托代码模型
JFlow流程 + 表单一体化 BPM(Java)(办理页前端外挂协议产品化)(流程事件基类 / 后端外挂)(模板事件配置:SQL/HTTP/脚本等)前端外挂 + 后端外挂 + 事件配置
Camunda / Flowable / Activiti:同一套「BPMN 扩展点」思维

三者同属 Activiti 谱系或其近亲,二开骨架高度相似:

层级典型落点
L2JavaDelegate(Service Task)、ExecutionListener(执行开始/结束)、TaskListener(人工任务 create/assignment/complete…)
L3BPMNextensionElements中配置 class / delegateExpression / expression / script;Script Task;条件表达式
L1引擎本身通常不强制提供与审批办理页对齐的「前端外挂协议」;表单与工作台多由业务系统自建,或依赖 Tasklist / 商业套件 / 自研前端

特点

  • L2/L3 极强:开发者友好,生态成熟,适合微服务与标准 BPMN。
  • L1 往往外置:若你的项目强依赖「办理页发送前校验、按钮定制、字段联动」的产品级协议,需要额外评估表单/门户方案。
  • External Task(Camunda 等)把重活外移到 Worker,适合解耦与多语言工人进程——这是 L2 的「进程外变体」,仍属服务侧挂接。
JFlow:把三层做成并列入口

JFlow 与下文 .NET 侧的 CCFlow同根同源、语言不同:事件名、分层思想、调度顺序一致,差异主要在 Java 包机制与 .NET 程序集机制。
产品概念上常称为:前端外挂(L1)、后端外挂(L2)、模板事件配置(L3)。详见第 6 节。

4.2 Java 阵营怎么读表

你更关心…相对更贴的路径
标准 BPMN + 强代码扩展 + 云原生 WorkerCamunda / Flowable
轻量嵌入、经典委托模型Activiti 谱系引擎
审批办理页也能产品级挂脚本,且配置/代码并列JFlow 这类一体化 BPM

5. 流行引擎怎么实现:.NET 阵营

5.1 总对照(.NET)

产品定位倾向L1 交互层L2 服务层L3 配置编排二开主叙事
Elsa Workflows通用长流程编排 + Studio中偏强(Studio 元数据/UIHint;业务办理页多自建)(Custom Activity、Middleware、Module/Feature)中(活动组合与表达式强;SQL/实施配置弱于 BPM)自定义 Activity 生态
Workflow Core轻量嵌入式流程库弱(几乎无产品级办理 UI)StepBody+ 中间件)中(JSON/YAML 引用 Step 类型)步骤即扩展单元
WorkflowEngine.NET可嵌入引擎(生产多需商业许可)(设计器模板 / 表单可定制)(Action Provider、Plugin、Custom Activity)(方案内 CodeActions 等)Action + Plugin
SlickflowBPMN 风格 .NET 引擎中(设计师可嵌;业务页多自建)(ExternalService、引擎 API)(本地类 / WebApi / SQL / 过程)节点 Action 多执行体
CCFlow流程 + 表单 + 组织一体化 BPM(Vue 前端外挂)FlowEventBase后端外挂)(设计器事件 + SQL/WebApi/过程等)前端外挂 + 后端外挂 + 事件配置
Elsa / Workflow Core:开发者编排优先
  • Elsa:二开主路径是「自定义积木」(Activity)+ 中间件 + 可打包扩展;对人机审批语义(会签、组织待办)通常要自建。
  • Workflow CoreStepBody即业务单元,嵌入成本低;几乎没有产品级设计器/表单/待办门户——二开 ≈ 写代码 + 自建 UI。
WorkflowEngine.NET / Slickflow:设计器与节点执行体
  • WorkflowEngine.NET:Action/Condition、CodeActions、Plugin、Custom Activity 文档完整;许可需单独评估。
  • Slickflow:节点上挂本地服务 / WebApi / SQL / 过程,BPMN 语义清晰;前端「办理页外挂协议」完整度因产品线而异。
CCFlow:与 JFlow 同一套三层协议

见下一节——用同源实现对 L1/L2/L3 做「可核对」说明,而不是把某一品牌写成唯一正确答案。

5.2 .NET 阵营怎么读表

你更关心…相对更贴的路径
自定义流程积木、云原生编排Elsa、Workflow Core
设计器内 Action / 商业嵌入WorkflowEngine.NET
BPMN 节点挂服务 / SQL / WebApiSlickflow
审批生命周期 + 办理页外挂 + 配置事件CCFlow / 同类一体化 BPM

6. 同源实证:JFlow(Java)与 CCFlow(.NET)如何落在三层上

二者事件模型同源:同一套事件语义(如发送前 / 发送成功 / 流程结束后),三种写法并列。
本节只做机制对照与源码索引,便于读者用公开实现核对「三层模型」是否可落地;不作为唯一选型结论。

6.1 概念映射

三层模型产品概念(JFlow / CCFlow)含义
L1 交互层前端外挂浏览器侧挂流程脚本:校验、按钮、提示、联动
L2 服务层后端外挂服务端强类型事件类:事务、改人、集成、审计
L3 配置层模板事件配置设计器挂 SQL / HTTP / 脚本 / 业务单元等

服务端调度思想(示意):全局拦截 → 流程级后端外挂 → 配置事件 → 消息推送(与业务事件共用时钟、职责分离)。

用户点击发送 ├─ ① L1:前端外挂(可拦截) └─ ② HTTP → 引擎发送编排 └─ 统一事件调度 ├─ 全局后端拦截 ├─ L2:流程事件基类(后端外挂) ├─ L3:FrmEvent / 数据源执行体(模板事件配置) └─ 消息推送(同事件标记,独立配置) └─ ③ L1:发送成功后的前端副作用

6.2 L1:前端外挂(以 CCFlow Vue3 为例)

约定:外挂类名以WGFlow_开头,并绑定流程号;与后端认同一套事件名(如SendWhen/SendSuccess)。

protected constructor(classID: string, flowNo: string) { if (classID.includes('WGFlow_') == false) { message.warning('外挂类名[' + classID + ']不符合规范,必须是以 WGFlow_ 开头.'); return; } super(classID); this.FlowNo = flowNo; }
适合说明
发送前弹窗校验、字段联动、按钮定制反馈在页面完成
发送成功后的提示 / 局部刷新不替代服务端写库

6.3 L2:后端外挂(.NET 与 Java 对照)

基类约定要点(两端一致):

  1. 子类重写事件方法与引擎交互
  2. 一个子类与一个(组)流程模板绑定FlowMark/getFlowMark
  3. 基类暴露运行时变量,降低重复查询
  4. 类进入约定程序集 / 包后由工厂发现

.NET Demo(CCFlow)

public class F065 : FlowEventBase { public override string FlowMark { get { return ",065,"; } } public override string SendWhen() { if (1 == 3) return "err@不符合流程发起条件,阻止流程发送。"; if (1 == 1) return "后端外挂 /App/Demo/F065 SendWhen 已经执行成功,节点ID:" + this.HisNode.NodeID + ",WorkID:" + this.WorkID;

Java Demo(JFlow)bp.App.Demo.WaiGua.WaiGuaFlow继承bp.wf.FlowEventBase,通过getFlowMark()绑定流程,重写SendWhen()等——与 .NET 侧同一设计。

适合说明
同步 ERP、改接收人、写台账强一致、可调试
全公司统一审计走全局拦截,而不是每个流程复制粘贴

6.4 L3:模板事件配置

在设计器为节点 / 流程 / 表单挂执行体,写入事件配置(如Sys_FrmEvent),执行体可为 SQL、WebApi、存储过程、事件类、业务单元等。

挂接点示例配置做法(L3)代码做法(L2)
发送前SQL 校验金额是否超限后端外挂复杂规则 + 改接收人
发送成功WebApi 同步外部系统后端外挂写第三方待办
流程结束过程归档后端关外部待办 + 前端提示

6.5 同源实现的启发(公平表述)

JFlow / CCFlow 证明了一件事:

三层挂接不必只存在于论文里——可以把 L1/L2/L3 做成同一事件时钟上的并列入口,让前端、后端、实施各走各的路,又在同一生命周期点汇合。

同时应看到边界:这类产品的扩展叙事偏「审批事件挂业务」,与 Elsa 那种「自定义画布 Activity 生态」不是同一赛道;选型时应按自己的主场景对齐,而不是按品牌热度对齐。


7. 用三层模型做选型:一张检查清单

评估任意引擎时,可用下面清单做「可核对」提问(建议对方给文档或样例,而不是口头承诺):

L1 交互层

  • 办理页是否有稳定的发送前 / 发送后钩子?
  • 能否定制按钮、提示、字段联动,且不改引擎前端内核
  • 前端事件名是否与后端生命周期对齐(或有明确映射表)?

L2 服务层

  • 能否在发送前拦截并回滚?
  • 能否读取并改写路由 / 接收人 / 流程变量?
  • 扩展是否按流程模板绑定,并可独立部署(程序集 / 包 / NuGet / jar)?
  • 是否区分「全局策略」与「单流程策略」?

L3 配置编排层

  • 设计器能否挂 SQL / HTTP / 脚本 / 表达式,而无需每次发版?
  • 配置执行体失败时,错误是否可观测、可阻断?
  • 简单集成走配置、复杂逻辑走代码,路径是否清晰?

跨层原则

  • 三层是否允许叠加,顺序是否文档化?
  • 消息推送与业务脚本是否解耦(同事件点、分职责)?
  • 升级引擎时,业务扩展目录是否默认不被覆盖?

8. 场景 × 层级:怎么选,而不是怎么站队

场景更优先的层原因
发送前弹窗、禁用按钮、字段联动L1反馈即时
同步 ERP、改接收人、写业务台账L2强一致、可调试
一条 SQL / 一个 HTTP 就能完成L3实施可配,最快
全公司统一审计 / 组织策略L2 全局一次拦截,全流程生效
前端团队强、后端紧L1 + L3交互与简单集成分流
后端团队强、要长期演进L2 为主可测试、可重构、可版本管理
标准 BPMN 微服务编排L2 Activity/Delegate + 可选 External Task积木与 Worker 更贴
政企审批 + 表单一体化交付L1+L2+L3 产品化是否齐全三层缺一都会转嫁成本

9. 结语

流程引擎的竞争力,不只在「把图画出来」,更在:

业务能不能稳稳挂上去——挂在交互层、服务层、还是配置层——并且始终不污染内核。

三层挂接模型给出的是一把跨产品、跨语言的尺子:

  • L1守人机边界
  • L2守系统真相
  • L3释放实施生产力

Java 阵营里,Camunda / Flowable / Activiti 把 L2/L3 做到了行业标杆,L1 多依赖外围表单与自建工作台;JFlow 则把三层做成办理页协议与设计器配置的并列能力。
.NET 阵营里,Elsa / Workflow Core 偏开发者编排,WorkflowEngine.NET / Slickflow 偏设计器与节点执行体,CCFlow 与 JFlow 同源,用前端外挂 / 后端外挂 / 事件配置覆盖三层。

没有绝对的第一名,只有与场景对齐的挂接方式。
选型时,把对方的名词翻译回 L1/L2/L3,再用第 7 节清单逐项核对——比比较口号更接近工程真相。


附录 A:术语速查

本文用语常见等价叫法
L1 交互层前端外挂、表单脚本、UI Hook、设计器插件
L2 服务层JavaDelegate、Listener、StepBody、Custom Activity、后端外挂、Action
L3 配置层事件配置、CodeAction、Script Task、表达式、SQL/HTTP 执行体
生命周期时钟事件列表、Listener event、发送前/后、任务 create/complete
不改内核业务在扩展点 / 外挂程序集 / 配置表,不在发送内核