从0到1掌握飞龙工作流FlowLong:分布式架构与核心技术解密
为什么选择FlowLong工作流引擎?
你是否还在为中国式复杂审批流程而头疼?传统工作流引擎要么功能过重难以集成,要么不支持中国特色审批场景。飞龙工作流FlowLong作为国产无代码工作流引擎的佼佼者,不仅支持30+种中国特色流程操作,还提供轻量级集成方案,完美适配Spring Boot与Solon生态。本文将深入剖析其架构设计与技术实现,助你快速掌握企业级工作流解决方案。
读完本文你将获得:
- 理解FlowLong的分层架构设计与核心组件交互
- 掌握流程引擎的核心技术点:流程定义、实例管理与任务调度
- 学会使用Spring Boot/Solon快速集成工作流功能
- 深入了解中国特色审批场景的实现方案
- 获取性能优化与分布式部署的最佳实践
FlowLong架构设计概览
整体架构图
flowchart TD
subgraph 接入层
A[Spring Boot Starter]
B[Solon Plugin]
end
subgraph 核心引擎层
C[FlowLongEngine 引擎接口]
D[ProcessService 流程定义服务]
E[RuntimeService 实例服务]
F[TaskService 任务服务]
G[QueryService 查询服务]
end
subgraph 业务逻辑层
H[流程解析器]
I[任务创建处理器]
J[条件节点处理器]
K[事件监听器]
end
subgraph 数据访问层
L[DAO接口]
M[MyBatis-Plus实现]
end
subgraph 存储层
N[MySQL]
O[PostgreSQL]
P[Oracle]
end
A --> C
B --> C
C --> D
C --> E
C --> F
C --> G
D --> H
E --> I
F --> J
G --> L
H --> K
I --> K
J --> K
L --> M
M --> N
M --> O
M --> P
核心模块功能说明
| 模块名称 | 核心功能 | 关键类 |
|---|---|---|
| flowlong-core | 工作流核心引擎实现 | FlowLongEngineImpl、Execution、FlowLongContext |
| flowlong-spring-boot-starter | Spring Boot集成支持 | FlowLongAutoConfiguration、SpelFlowLongExpression |
| flowlong-solon-plugin | Solon框架集成支持 | XPluginImpl、SolonFlowLongExpression |
| flowlong-mybatis-plus | 数据访问层实现 | 各DAO接口的MyBatis-Plus实现类 |
| flowlong-spring-boot-example | Spring Boot示例 | TestController、TestConfig |
| flowlong-solon-example | Solon示例 | TestController、FlowLongApplication |
技术栈选型
| 技术领域 | 选型 | 优势 |
|---|---|---|
| 核心框架 | Java + Maven/Gradle | 跨平台、生态丰富 |
| 依赖注入 | Spring/Solon | 轻量级集成、低侵入 |
| ORM框架 | MyBatis-Plus | 简化CRUD操作、性能优秀 |
| 表达式解析 | Spring EL/自定义表达式 | 支持复杂业务规则计算 |
| 数据库支持 | MySQL/Oracle/PostgreSQL | 多数据库适配、企业级支持 |
| 缓存机制 | 本地缓存 | 提高流程定义查询性能 |
| 任务调度 | 定时任务 | 支持超时审批、自动提醒 |
核心组件详解
FlowLongEngine引擎接口
FlowLongEngine作为核心引擎接口,定义了工作流引擎的所有核心操作,包括流程实例的创建、任务执行、跳转与驳回等功能。其设计采用了接口隔离原则,将不同职责的功能划分为多个服务接口。
public interface FlowLongEngine {
// 流程实例启动方法族
Optional<FlwInstance> startInstanceById(Long id, FlowCreator flowCreator, Map<String, Object> args, boolean saveAsDraft, Supplier<FlwInstance> supplier);
// 任务执行方法族
boolean executeTask(Long taskId, FlowCreator flowCreator, Map<String, Object> args);
// 流程跳转方法
default boolean executeJumpTask(Long taskId, String nodeKey, FlowCreator flowCreator, Map<String, Object> args) {
return this.executeJumpTask(taskId, nodeKey, flowCreator, args, TaskType.jump).isPresent();
}
// 驳回操作方法
Optional<List<FlwTask>> executeRejectTask(FlwTask currentFlwTask, String nodeKey, FlowCreator flowCreator, Map<String, Object> args, boolean termination);
// 更多核心方法...
}
四大核心服务
FlowLong将核心功能划分为四大服务接口,职责清晰,便于扩展:
-
ProcessService - 流程定义服务
- 流程部署与版本管理
- 流程定义查询与删除
- 模型缓存管理
-
RuntimeService - 流程实例服务
- 流程实例创建与启动
- 实例变量管理
- 流程重启与终止
-
TaskService - 任务服务
- 任务执行与跳转
- 任务分配与委派
- 加签与减签操作
-
QueryService - 查询服务
- 流程实例查询
- 任务状态查询
- 历史数据查询
核心上下文设计
FlowLongContext作为全局上下文,维护了引擎的所有配置与组件引用,采用单例模式确保全局唯一性。
public class FlowLongContext {
// 服务组件
private ProcessService processService;
private RuntimeService runtimeService;
private TaskService taskService;
private QueryService queryService;
// 配置参数
private FlowLongProperties properties;
// 处理器与策略
private CreateTaskHandler createTaskHandler;
private ConditionNodeHandler conditionNodeHandler;
private TaskAccessStrategy taskAccessStrategy;
// 工具类
private FlowLongExpression flowLongExpression;
private FlowJsonHandler flowJsonHandler;
// 上下文管理方法...
}
流程引擎核心技术解析
流程定义与解析
FlowLong采用JSON格式定义流程模型,通过ProcessModelParser将JSON转换为内存中的ProcessModel对象。
sequenceDiagram
participant Client
participant ProcessService
participant ProcessModelParser
participant FlowCache
participant Repository
Client->>ProcessService: 部署流程定义(JSON)
ProcessService->>ProcessModelParser: 解析JSON
ProcessModelParser->>ProcessModel: 构建对象模型
ProcessModelParser->>FlowCache: 缓存ProcessModel
ProcessService->>Repository: 保存流程定义
核心解析代码:
public class DefaultProcessModelParser implements ProcessModelParser {
@Override
public ProcessModel parse(String content, String cacheKey, boolean redeploy) {
// 从缓存获取
ProcessModel processModel = getFlowCache().get(cacheKey);
if (null != processModel && !redeploy) {
return processModel;
}
// JSON解析为ProcessModel对象
processModel = FlowLongContext.fromJson(content, ProcessModel.class);
// 构建节点关系
processModel.buildParentNode(processModel.getRootNode());
// 缓存流程模型
getFlowCache().put(cacheKey, processModel);
return processModel;
}
}
流程实例执行流程
流程实例的执行是工作流引擎的核心,涉及状态管理、任务创建、流转控制等关键环节。
flowchart TD
A[启动流程实例] --> B[解析流程模型]
B --> C[创建初始任务]
C --> D[任务分配给处理人]
D --> E[等待任务执行]
E --> F{任务操作类型}
F -->|正常通过| G[执行节点出口规则]
F -->|驳回| H[回退到指定节点]
F -->|跳转| I[跳转到目标节点]
G --> J[判断是否结束]
H --> D
I --> D
J -->|是| K[结束流程实例]
J -->|否| L[创建下一节点任务]
L --> D
核心执行代码:
public class RuntimeServiceImpl implements RuntimeService {
@Override
public FlwInstance createInstance(FlwProcess flwProcess, FlowCreator flowCreator,
Map<String, Object> args, NodeModel nodeModel,
boolean saveAsDraft, Supplier<FlwInstance> supplier) {
// 创建流程实例对象
FlwInstance flwInstance = supplier != null ? supplier.get() : new FlwInstance();
// 设置基本属性
flwInstance.setProcessId(flwProcess.getId());
flwInstance.setProcessKey(flwProcess.getProcessKey());
flwInstance.setProcessName(flwProcess.getProcessName());
flwInstance.setTenantId(flowCreator.getTenantId());
flwInstance.setBusinessKey(flwInstance.getBusinessKey());
flwInstance.setPriority(InstancePriority.DEFAULT);
// 处理变量
if (MapUtils.isNotEmpty(args)) {
flwInstance.putAllVariable(args);
}
// 保存实例
saveInstance(flwInstance, flwProcess, saveAsDraft, flowCreator);
// 如果不是暂存,则创建初始任务
if (!saveAsDraft) {
Execution execution = new Execution();
execution.setFlowCreator(flowCreator);
execution.setArgs(args);
execution.setProcessModel(getProcessModel(flwProcess));
// 创建初始任务
createStartTask(flwInstance, nodeModel, execution);
}
return flwInstance;
}
}
中国特色审批场景实现
FlowLong专为中国特色审批流程设计,支持30+种特殊操作,以下是几种典型场景的实现方案:
会签功能实现
会签功能支持顺序会签、并行会签、或签和票签四种模式,通过PerformType枚举控制行为:
public enum PerformType {
SEQUENTIAL(1, "顺序会签"),
PARALLEL(2, "并行会签"),
OR(3, "或签"),
VOTE(4, "票签");
private final int value;
private final String desc;
// 枚举实现...
public static PerformType get(Integer value) {
if (value == null) {
return null;
}
for (PerformType type : values()) {
if (type.value == value) {
return type;
}
}
return null;
}
}
并行会签处理逻辑:
public void handleParallelSign(Execution execution, NodeModel nodeModel, FlwTask currentTask) {
// 获取该节点的所有任务
List<FlwTask> nodeTasks = taskService.getTasksByInstanceIdAndNodeKey(
currentTask.getInstanceId(), nodeModel.getNodeKey());
// 检查是否所有任务都已完成
boolean allCompleted = nodeTasks.stream()
.allMatch(task -> TaskState.COMPLETED.equals(TaskState.get(task.getTaskState())));
// 检查是否有拒绝任务
boolean hasRejected = nodeTasks.stream()
.anyMatch(task -> TaskState.REJECT.equals(TaskState.get(task.getTaskState())));
if (hasRejected) {
// 如有拒绝,执行驳回流程
execution.setTaskEventType(TaskEventType.REJECT);
rejectionHandler.handleRejection(execution, currentTask, nodeModel);
} else if (allCompleted) {
// 所有同意,继续流程
execution.setCurrentNodeKey(nodeModel.getNodeKey());
flowRouter.route(execution);
}
}
驳回策略实现
FlowLong支持三种驳回策略,通过灵活的节点回溯机制实现:
flowchart TD
A[当前任务] --> B{驳回策略}
B -->|退回上一步| C[查找上一节点]
B -->|退回发起人| D[查找开始节点]
B -->|任意节点| E[选择目标节点]
C --> F[创建退回任务]
D --> F
E --> F
F --> G[更新当前流程状态]
快速集成指南
Spring Boot集成步骤
- 添加依赖
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>flowlong-spring-boot-starter</artifactId>
<version>最新版本</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
- 配置数据库
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowlong?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
flowlong:
# 流程引擎配置
process-definition-cache-seconds: 3600
# 任务分配策略
task-assign-strategy: role_first
# 自动审批配置
auto-approve:
enabled: true
expire-time: 86400000
- 创建流程定义
@RestController
@RequestMapping("/process")
public class ProcessController {
@Autowired
private ProcessService processService;
@PostMapping("/deploy")
public Result deployProcess(@RequestBody ProcessDefinitionRequest request) {
// 部署流程定义
FlwProcess process = processService.deploy(
request.getName(),
request.getKey(),
request.getJsonDef(),
FlowCreator.of(SecurityUtils.getCurrentUserId(), SecurityUtils.getCurrentUserName())
);
return Result.success(process);
}
}
- 启动流程实例
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private FlowLongEngine flowLongEngine;
@Override
@Transactional
public Order createOrder(OrderDTO orderDTO) {
// 保存订单
Order order = saveOrder(orderDTO);
// 启动流程实例
FlowCreator creator = FlowCreator.of(
SecurityUtils.getCurrentUserId(),
SecurityUtils.getCurrentUserName()
);
// 流程参数
Map<String, Object> args = new HashMap<>();
args.put("orderId", order.getId());
args.put("amount", order.getAmount());
args.put("assignee", orderDTO.getManagerId());
// 启动流程
Optional<FlwInstance> instance = flowLongEngine.startInstanceByProcessKey(
"order_approval", // 流程定义Key
creator,
args
);
// 关联流程实例ID
order.setProcessInstanceId(instance.get().getId());
orderMapper.updateById(order);
return order;
}
}
- 处理任务
@RestController
@RequestMapping("/task")
public class TaskController {
@Autowired
private TaskService taskService;
@PostMapping("/complete")
public Result completeTask(@RequestBody CompleteTaskRequest request) {
FlowCreator creator = FlowCreator.of(
SecurityUtils.getCurrentUserId(),
SecurityUtils.getCurrentUserName()
);
Map<String, Object> args = new HashMap<>();
args.put("comment", request.getComment());
args.put("approvalResult", request.getApprovalResult());
boolean success = taskService.executeTask(request.getTaskId(), creator, args);
return success ? Result.success() : Result.error("任务处理失败");
}
@PostMapping("/reject")
public Result rejectTask(@RequestBody RejectTaskRequest request) {
FlowCreator creator = FlowCreator.of(
SecurityUtils.getCurrentUserId(),
SecurityUtils.getCurrentUserName()
);
Map<String, Object> args = new HashMap<>();
args.put("comment", request.getComment());
FlwTask task = taskService.getTaskById(request.getTaskId());
Optional<List<FlwTask>> result = flowLongEngine.executeRejectTask(
task,
request.getTargetNodeKey(),
creator,
args
);
return result.isPresent() ? Result.success() : Result.error("驳回失败");
}
}
Solon集成示例
Solon集成与Spring Boot类似,主要区别在于 starter 依赖和配置方式:
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>flowlong-solon-plugin</artifactId>
<version>最新版本</version>
</dependency>
@Configuration
public class AppConfig {
@Bean
public void flowlongConfig() {
// Solon中配置FlowLong
FlowLongContext context = new FlowLongContext();
context.setFlowLongExpression(new SolonFlowLongExpression());
context.setFlowJsonHandler(new SolonFlowJsonHandler());
// 其他配置...
FlowLongEngine engine = new FlowLongEngineImpl().configure(context);
Aop.wrapAndPut(FlowLongEngine.class, engine);
}
}
性能优化与分布式部署
性能优化策略
- 流程定义缓存
FlowLong默认缓存流程定义到本地内存,减少数据库访问:
@Configuration
public class FlowLongConfig {
@Bean
public ProcessModelParser processModelParser() {
DefaultProcessModelParser parser = new DefaultProcessModelParser();
// 设置缓存过期时间为2小时
parser.setCacheSeconds(7200);
return parser;
}
}
- 数据库优化
关键表索引设计:
-- 任务表索引
CREATE INDEX idx_task_instance_id ON flw_task(instance_id);
CREATE INDEX idx_task_actor_id ON flw_task(actor_id);
CREATE INDEX idx_task_create_time ON flw_task(create_time);
-- 实例表索引
CREATE INDEX idx_instance_business_key ON flw_instance(business_key);
CREATE INDEX idx_instance_process_key ON flw_instance(process_key);
- 异步处理
对于耗时操作采用异步处理:
@Service
public class AsyncTaskService {
@Async
public CompletableFuture<Void> asyncCompleteTask(Long taskId, FlowCreator creator, Map<String, Object> args) {
taskService.executeTask(taskId, creator, args);
return CompletableFuture.runAsync(() -> {
// 发送通知等后续操作
notificationService.sendTaskCompletedNotification(taskId);
});
}
}
分布式部署方案
在分布式环境下,FlowLong通过数据库悲观锁保证任务操作的原子性:
public class DistributedTaskLock implements TaskLock {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public boolean tryLock(Long taskId, String userId, long timeout) {
try {
// 使用数据库悲观锁
jdbcTemplate.update(
"UPDATE flw_task SET lock_user_id = ?, lock_time = NOW() WHERE id = ? AND lock_user_id IS NULL",
userId, taskId
);
// 检查是否成功获取锁
Integer count = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM flw_task WHERE id = ? AND lock_user_id = ?",
Integer.class, taskId, userId
);
return count != null && count > 0;
} catch (Exception e) {
log.error("获取任务锁失败", e);
return false;
}
}
@Override
public void releaseLock(Long taskId, String userId) {
jdbcTemplate.update(
"UPDATE flw_task SET lock_user_id = NULL, lock_time = NULL WHERE id = ? AND lock_user_id = ?",
taskId, userId
);
}
}
常见问题与解决方案
问题1:任务分配失败
可能原因:
- 流程定义中未正确设置处理人
- 任务分配策略配置错误
- 用户/角色信息未正确加载
解决方案:
@Configuration
public class TaskAssignConfig {
@Bean
public TaskActorProvider taskActorProvider() {
return new CustomTaskActorProvider();
}
public static class CustomTaskActorProvider implements TaskActorProvider {
@Override
public Integer getActorType(NodeModel nodeModel) {
// 自定义处理人类型判断逻辑
if (nodeModel.getExtendConfig().containsKey("roleId")) {
return ActorType.ROLE.getValue();
} else if (nodeModel.getExtendConfig().containsKey("deptId")) {
return ActorType.DEPARTMENT.getValue();
}
return ActorType.USER.getValue();
}
}
}
问题2:流程实例启动失败
排查步骤:
- 检查流程定义JSON是否正确
- 验证流程模型是否包含开始节点
- 检查数据库连接是否正常
- 查看日志中的具体错误信息
示例修复:确保流程定义包含正确的开始节点:
{
"nodeKey": "start",
"nodeName": "开始",
"nodeType": "startEvent",
"nextNodeKeys": ["approve"],
"extendConfig": {}
}
问题3:并行网关死锁
解决方案:优化并行分支汇聚条件:
public class OptimizedJoinGatewayHandler implements JoinGatewayHandler {
@Override
public boolean canProceed(Execution execution, NodeModel nodeModel) {
String instanceId = execution.getInstanceId();
String nodeKey = nodeModel.getNodeKey();
// 查询所有进入分支的完成情况
List<String> incomingNodes = nodeModel.getIncomingNodeKeys();
long completedCount = incomingNodes.stream()
.filter(nk -> taskService.countCompletedTasks(instanceId, nk) > 0)
.count();
// 所有分支完成才继续
return completedCount == incomingNodes.size();
}
}
总结与展望
FlowLong作为一款专为中国特色审批流程设计的工作流引擎,通过灵活的架构设计和丰富的功能支持,为企业提供了开箱即用的工作流解决方案。其核心优势在于:
- 轻量级架构:无侵入式集成,易于上手和扩展
- 丰富的中国特色功能:支持30+种中国式审批场景
- 多框架支持:同时支持Spring Boot和Solon生态
- 高性能设计:通过缓存和优化查询提升系统性能
- 完善的文档和示例:降低学习和使用门槛
未来,FlowLong将继续在以下方向发展:
- 引入分布式缓存替代本地缓存,提升集群性能
- 支持流程设计器与引擎的低代码集成
- 增强AI辅助流程设计功能
- 提供更多行业解决方案模板
参考资源
- 官方文档:https://flowlong.aizuda.com
- 设计器在线演示:https://flowlong-desginer.pages.dev
- 源码仓库:https://gitcode.com/aizuda/flowlong
- 示例项目:flowlong-spring-boot-example 和 flowlong-solon-example
通过本文的介绍,相信你已经对FlowLong的架构设计和核心技术有了深入了解。现在就开始动手实践,将工作流能力集成到你的项目中,提升业务流程的自动化水平和效率!
如果觉得本文对你有帮助,请点赞、收藏并关注作者,获取更多工作流技术干货!下一期我们将深入探讨FlowLong的事件监听机制与扩展点开发,敬请期待。
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00
GLM-4.7-FlashGLM-4.7-Flash 是一款 30B-A3B MoE 模型。作为 30B 级别中的佼佼者,GLM-4.7-Flash 为追求性能与效率平衡的轻量化部署提供了全新选择。Jinja00
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
KuiklyUI基于KMP技术的高性能、全平台开发框架,具备统一代码库、极致易用性和动态灵活性。 Provide a high-performance, full-platform development framework with unified codebase, ultimate ease of use, and dynamic flexibility. 注意:本仓库为Github仓库镜像,PR或Issue请移步至Github发起,感谢支持!Kotlin07
compass-metrics-modelMetrics model project for the OSS CompassPython00