Skip to content

设计原理 01 · 架构总览

系列:jeeflow 工作流引擎设计原理 阅读前提:已了解 SPEC.md 的数据模型与流程定义格式

1. 为什么这么设计

工作流引擎的本质是:把"流程定义"变成"一系列待办任务"。围绕这个本质,jeeflow 的架构做了三个关键决策:

决策一:引擎核心零框架依赖

不做为什么
不依赖 ORM存储是 SPI,引擎不关心 SQL/方言
不依赖 Web 框架引擎是纯逻辑库,HTTP 是 demo 的事
不依赖 DI 容器用 HandlerRegistry(自写 IoC)替代
不依赖表达式库决策表达式走 SPI,业务方自己选实现

结果:jeeflow-core 只有 slf4j 一个可选依赖,四版引擎核心都是纯标准库。可以嵌入任何项目(Spring Boot / 原生 Java / 微服务)。

决策二:领域逻辑收敛到聚合根(DDD)

不采用"贫血模型 + 上帝服务类"(逻辑全堆在 EngineImpl),而是:

任务状态转换、任务创建、驳回、完成 —— 都是 ProcessInstance / ProcessTask 的行为
引擎只做三件事:解析流程定义、遍历节点、调用聚合根

详见 02-领域模型

决策三:引擎不做业务决策,只定契约

引擎不自动执行第一个任务、不决定驳回后怎么办——这些是调用方的约定:

  • startAndExecute:启动后自动完成申请节点(调用方实现)
  • submitType=2(REJECT):跳结束(实例 45);退回发起人用 submitType=6(调用方实现)

引擎与调用方的边界详见 06-契约约定

2. 分层架构

┌─────────────────────────────────────────────────┐
│                  调用方(业务层)                  │
│   demo API / 业务服务 / jeeflow-ui              │
└──────────────────────┬──────────────────────────┘
                       │ 遵守契约(startAndExecute / submitType)
┌──────────────────────▼──────────────────────────┐
│              引擎编排层(EngineImpl)             │
│   · 加载/解析流程定义(LogicFlow JSON → FlowModel)│
│   · 节点遍历(executeNode / followEdges)         │
│   · 决策求值(表达式 / Registry / 扩展)           │
│   · 参与者解析(assignee / assignmentHandler)    │
│   · 事件发布 / 拦截器调度                          │
├─────────────────────────────────────────────────┤
│              领域层(DDD 聚合根)                  │
│   ProcessInstance:completeTask / finish / reject│
│   ProcessTask:finish / abandon / isAllowed      │
├─────────────────────────────────────────────────┤
│               SPI 接口层                         │
│   ProcessRepository(必须)                      │
│   UserProvider / IDGenerator / ExprEvaluator    │
└──────────────────────┬──────────────────────────┘
                       │ 依赖注入(构造器 / 注册表)
┌──────────────────────▼──────────────────────────┐
│              仓储实现(适配层)                    │
│   内存仓储(测试) / JDBC / MyBatis / SQLAlchemy  │
└─────────────────────────────────────────────────┘

依赖方向(自上而下单向):

调用方 → 引擎编排层 → 领域层 → SPI → 仓储实现

领域层不依赖引擎层(聚合根不知道 EngineImpl 的存在);引擎层依赖领域层和 SPI;仓储实现依赖 SPI。

3. 一次请求的生命周期

以"启动流程"为例,时序:

调用方                  EngineImpl                 ProcessInstance         Repository
  │  startAndExecute      │                           │                      │
  │──────────────────────▶│                           │                      │
  │                       │ findDefineById ──────────▶│                      │
  │                       │ JSON → FlowModel           │                      │
  │                       │ create(工厂)─────────────▶│                      │
  │                       │ saveInstance ─────────────▶│                      │
  │                       │ 事件:PROCESS_START         │                      │
  │                       │ executeNode(start)          │                      │
  │                       │   └─ followEdges            │                      │
  │                       │   └─ createTask(工厂)────▶│                      │
  │                       │   └─ saveTask ─────────────▶│                      │
  │                       │ 完成申请节点(契约)          │                      │
  │                       │   └─ completeTask ─────────▶│                      │
  │                       │   └─ updateTask ───────────▶│                      │
  │                       │ 事件:TASK_COMPLETE          │                      │
  │                       │ executeNode(审批节点)         │                      │
  │◀──────────────────────│ 返回 ProcessInstance         │                      │

4. 四语言模块对照

同一套架构,四个语言的落点:

JavaGoNode.jsPython
引擎编排core/JeeflowEngineImpl.javaengine/engine_impl.gosrc/engine.tsjeeflow/engine.py
领域层domain/ProcessInstance.javamodel/instance.gosrc/model.tsjeeflow/model.py
SPIspi/IProcessRepository.javaspi/spi.gosrc/spi.tsjeeflow/spi.py
扩展interceptor/ event/engine/interceptor.gosrc/extensions.tsjeeflow/extensions.py
Registryinterceptor/AssignmentHandlerengine/registry.gosrc/registry.tsjeeflow/extensions.py
内存仓储test 模块memory/src/memory.tsjeeflow/memory.py
demojeeflow-demo-boot4/cmd/demo/demo/demo/
前端

前端统一由 jeeflow-ui 提供(Vue3 + mldong-flow-designer-plus),对接任一后端。

5. 关键源码位置(锚点)

主题JavaGoNode.jsPython
引擎入口core/JeeflowEngineImpl.javaengine/engine_impl.gosrc/engine.tsjeeflow/engine.py
聚合根domain/ProcessInstance.javamodel/instance.gosrc/model.tsjeeflow/model.py
仓储 SPIspi/IProcessRepository.javaspi/spi.gosrc/spi.tsjeeflow/spi.py
内存仓储test/.../MemoryProcessInstanceRepository.javamemory/repository.gosrc/memory.tsjeeflow/memory.py
流程定义解析model/*.javamodel/types.gosrc/model.tsjeeflow/model.py
合规测试test/.../JeeflowEngineTest.javaengine_test.go__tests__/spec.test.tstests/spec_test.py

6. 与其他语言差异备忘

差异点说明
Go 命名导出方法 PascalCase(FindDefineByID),语义与 Java camelCase 一致
Python 命名全部 snake_case(find_define_by_id
Node/Python 异步引擎方法返回 Promise / await;Go/Java 同步
Node 领域层ProcessInstance 是 class(interface 无法承载行为);仓储克隆时用 cloneInstance 保留原型
Python 领域层dataclass + 方法(行为与 class 等价,字段声明更简洁)

下一篇02 · 领域模型——为什么把逻辑收敛到聚合根

jeeflow · 轻量级多语言工作流引擎