☰
Activiti还是Flowable?工作流引擎选型与落地避坑指南
2026/10/12 8:39:46 网站建设 项目流程

做Java后端这么多年,被问得最多的工作流问题就是“Activiti和Flowable到底选哪个”。这俩引擎像一对双胞胎,代码风格像、表结构像、连BPMN解析器都很像,但真到业务选型的时候,各自的路线和生态已经拉开了明显差距。这篇文章不打算按教科书思路去罗列功能点,而是站在实际落地和二次开发的角度,讲清楚怎么选、怎么集成、以及选完后最常见的几个坑怎么处理好。正在做技术选型的,或者已经在老项目里被Activiti折磨过的朋友,应该都能从里面找到自己能用的内容。

如果你刚接触工作流引擎,可以先把这个当一篇带避坑的入门指南;如果你已经在跑流程业务,后两章关于迁移、追回和性能排查的内容会更对口。我尽量少说空话,把我自己项目里验证过的做法和踩过的坑写出来,这样大家抄作业也能抄得放心。

1. 两个引擎的前世今生:同一个爹,分了两条路

1.1 从源头上看:为什么它们长得这么像

Activiti最早是从JBoss jBPM4的社区代码里演化出来的,主打轻量、可嵌入、对Spring友好,当年很多Java项目的审批流都是靠它跑起来的。后来Activiti团队内部有几位核心成员,包括一些参与早期5.x版本设计的人,出来创建了Flowable项目。所以Flowable最初就是从Activiti 5.0的代码库里fork出来的,这也就解释了为什么你在网上搜“Activiti和Flowable的区别”,大多数文章都会说“API几乎一样”。

这个源流关系看起来只是背景知识,实际上对选型影响很大。因为fork之后就分家了,Activiti 6继续在传统BPMN流程上打磨,Activiti 7则开始大幅度拥抱云原生和微服务,到了Activiti 8更是把Spring Boot风格的东西融入到核心代码里。Flowable则基本保持了Activiti 5.x那一套轻量易用的内核,在发展上更偏企业业务流程平台,陆续完善了CMMN、DMN、表单集成这些能力。用一个生活化的类比,这就好比两个程序员分叉了同一套代码库,一个天天在搞服务拆分和容器化,另一个专心把业务功能做深做稳。维护者都希望自己的分支最优,但用户侧感受到的路径是完全不同的。

所以选型之前先看清楚你自己想要的是什么:是跟着云原生节奏走,还是需要一个稳定、业务功能更全面的流程引擎。很多人在这两个引擎之间反复纠结,其实是被“同源”误导了。你要明白它们分家后的目标市场并不完全一样,这比单纯比功能点更能帮助你做决定。

1.2 内核和表结构:延续了共同的基因

两个引擎的核心架构都保留了早期Activiti的基因:ProcessEngine是总入口,RepositoryService管流程定义,RuntimeService管流程实例执行,TaskService管任务,HistoryService查历史。这套抽象真的很经典,后人在学习和排查时能省不少事,也是为什么很多老Java工程师拿到Flowable也能很快上手。数据库表结构大同小异,都以ACT_开头,ACT_RE_是流程定义和模型资源,ACT_RU_是运行期数据,ACT_HI_是历史数据,ACT_ID_是用户和组,ACT_EVT_是事件。如果你之前做过Activiti的二次开发,按着这套表结构去理解Flowable基本不会迷路。

但要注意,分家之后两边在字段和索引上已经有了一些细微差异。Flowable的历史数据记录维度更细,比如ACT_HI_DETAIL会记录更完整的变量变更轨迹,用于追回、驳回和审计会更方便。很多团队想直接靠改import包名从Activiti迁到Flowable,这是不现实的。虽然API结构相似,但包名从org.activiti变到org.flowable,而且内部命令、事件、监听器接口都有不少变化。比较稳妥的做法是,在应用层包一个自己的工作流服务接口,把引擎相关的调用都收口到实现类里,以后真的需要换引擎时,影响面可以控制在一个模块内。

1.3 版本差异与演进路线:从6.x到8.x怎么选

Flowable从6.x起步,目前7.x已经发布,但6.8.x仍然是很多生产项目的主流选择。Activiti从5.x到6.x再到7.x、8.x,版本跨度更大,每个大版本的核心代码都做了不少调整。如果你看到网上教程里写的是Activiti 5,直接搬到Activiti 7项目里大概率会跑不起来,因为包名、配置项、API都有变化。而Flowable的升级路径相对平滑,很多基于5.x时代写法的代码,迁移到6.x只需要小幅改动,这也是企业敢用它的原因之一。

版本选择上,我建议不要追最新。Flowable选择6.8.x这类企业常用的维护版本,Activiti则要看你的Spring Boot版本是否匹配。引擎本身不是越新越稳,你要的是社区补丁更充分、别人踩坑更多、可查资料更丰富的版本。如果一个版本刚刚发布,就算功能再吸引人,也应该先在测试环境压上一个月再说。换一个角度,选型时真正要确认的是业务模型和BPMN规范是否贴合。如果业务一直都在做标准三节点审批,两个引擎所有版本的差异都可以忽略;如果要处理任务编排、案例管理,那就要认真比较CMMN和DMN的支持程度。

2. 业务选型核心维度:别光看功能清单,还要看坑

2.1 功能特性对照:从会签、追回到动态表单

做选型的人容易先把两个引擎的功能列表拉出来比,这个方向没问题,但不能光比“有没有”,还要比“好不好实现”。

功能点ActivitiFlowable选型影响
BPMN 2.0核心流程支持全面支持全面无明显差异
并行网关/排他网关成熟成熟无明显差异
会签/或签(多实例)支持支持更灵活Flowable对集合分配处理更好
驳回/任意节点跳转需自研需自研但API更顺手Flowable实现成本略低
流程追回/撤回需自研需自研但可基于状态机Flowable历史数据支持更好
CMMN案例管理较弱较成熟非结构化流程选Flowable
DMN决策表较弱较成熟有规则引擎需求选Flowable
动态表单/表单集成中等较成熟Flowable周边模块更多
Spring Boot集成7.x后增强非常成熟Flowable传统更稳
历史查询能力够用更细粒度审计、追回场景Flowable占优

从这张表能看出,在标准BPMN场景下两者几乎难分伯仲,真正的分水岭在于那些“引擎默认不提供但业务一定会提”的高级操作,比如流程追回、驳回上一步、退回发起人、加签转办。我单独说下流程追回,因为这在审批系统里真的太常用了。Activiti和Flowable原生都没封装一个叫“追回”的方法,都需要自己通过历史节点信息和流程实例状态去实现。Flowable在这块的优势是历史数据记录得全,拿到“上一个任务节点”“上一条流转线”很容易,而且它有专门的状态变更API可以控制活动节点迁移,写起来没那么别扭。如果你的业务侧几乎每张审批单都可能要追回,那从实现成本看,Flowable会是更省事的选择。

2.2 性能和资源占用:别只看压测数字

很多技术选型文档会把两个引擎的benchmark数据拿出来说,但项目与项目之间的差异太大,这种数字参考意义有限。我在实际项目里观察到的规律是这样的:在几百名员工规模的企业场景里,几十个流程定义、单个流程实例节点数不超过二十个,Activiti和Flowable的性能表现几乎感知不出差别。瓶颈通常不是引擎本身,而是数据库连接池、历史表索引、以及业务代码里有没有在流程节点执行时同步调外部系统。

真正需要关注的是长跑之后的数据膨胀。Activiti和Flowable都会保留大量历史数据,比如ACT_HI_TASKINST、ACT_HI_PROCINST和ACT_HI_DETAIL,如果项目上线几个月不做归档,查询效率会急剧下降。Flowable因为历史记录更细,膨胀速度理论上会更快一点,但换来的是后续做驳回追回和流程审计时更从容。所以选型时要把“有没有人愿意做数据归档”也当成考量项,否则再好的引擎也会被慢查询拖垮。

并发处理方面,两个引擎默认都采用乐观锁,高并发下偶尔会遇到OptimisticLockingException,这本身不是缺陷,反而是防止并发修改一致性问题的手段。如果你的系统在某个节点会有很多人同时操作同一流程实例,建议在应用层先加一把业务锁,而不只是依赖数据库乐观锁,否则体验很差。这一点无论选哪个引擎都要记住。

2.3 团队沉淀、社区热度和生态捆绑不能不看

选型不是选“哪个最新”,而是选“团队最容易长期维护的那个”。如果团队里已经有几位同事对Activiti的表结构和API很熟,而且系统已经在生产环境稳定运行,那么哪怕Flowable听起来更好,也不建议轻易推倒重来。换引擎不只是替换依赖,还涉及流程定义迁移、历史数据兼容、监听器重写、甚至可能牵动权限体系,成本往往被低估。反过来讲,新项目从零开始,我确实更建议倾向Flowable,原因不只是技术,而是生态和社区热度。

这几年你在搜索引擎里搜“Flowable快速入门”“Flowable Spring Boot集成UI”“Flowable工作流条件设置”,中英文资料都很多,而且很多基于JeecgBoot的低代码二次开发项目也把Flowable列为推荐的流程引擎方案。这意味着招人、问问题、找现成代码都更容易。对一个长期维护的项目来说,生态热度带来的隐性收益是很实在的。

我还想提醒一点,不要在选型阶段就执拗于“必须一百年不换”。技术是在流动的,更合理的方式是先把引擎封装到业务代码后面,让业务代码不直接依赖ProcessEngine、RuntimeService这些类。这样即使三年后要迁移,大部分业务逻辑还能保住,而不是把整个项目锁定在一个厂商概念上。

3. 落地实操:Spring Boot集成、UI设计器和JeecgBoot避坑

3.1 Spring Boot快速集成Flowable:5分钟搭一个最小可用流程

先从最繁琐的Spring Boot集成说起。很多同学第一次接触Flowable,会去搜“Flowable详细使用教程”,看到一大堆模块就发怵。其实最简单的情况下,只需要一个依赖加一点配置就能启动。

<dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.8.0</version> </dependency>

如果你本地是MySQL,用下面这份配置就能把引擎跑起来。

spring: datasource: url: jdbc:mysql://localhost:3306/flowable_demo?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root flowable: database-schema-update: true history-level: audit async-executor-activate: false check-process-definitions: false

第一次启动时,Flowable会自动创建ACT_*和FLW_*这些表。这里有几个容易犯的错,我一个个说。首先是database-schema-update,本地开发可以开true,但生产环境一定要关掉,改成由Flyway、Liquibase或者专门的DBA流程去管理。否则一次系统发布的版本变化,可能导致引擎自动给数据表加字段,这种隐式变更在授权审计和故障恢复时都是大麻烦。

其次是history-level,Flowable支持四个历史级别:none、activity、audit、full。我建议默认至少用audit,它能记录流程实例和任务实例的完整节点信息,是做流程追回和驳回的前提。如果还需要完整变量历史,特别是后面要做超时统计、追溯某个审批人改了什么字段,那就直接开full。但全量历史会让数据量涨得很快,所以对应的归档策略也得跟上。

最后是async-executor-activate。如果暂时用不到异步任务,先关掉,因为它会起后台定时线程扫描异步作业,流量小的时候看不出问题,一旦积压严重反而拖垮数据库。等真正需要异步任务或事件子流程时,再按需打开。依赖和配置就绪后,写一个Test类,注入RepositoryService和RuntimeService,部署一个最简单的BPMN XML,流程就能跑起来。整个过程十来分钟能见到效果,这也是为什么Flowable的快速入门在企业开发圈里口碑不错。

3.2 Flowable UI和在线流程设计器:适合本地演示,生产要另想办法

“Spring Boot集成Flowable UI”是搜索热度很高的一个话题,因为大家天然希望有一个能拖拽画流程的界面。Flowable官方确实有一个flowable-ui的独立应用,里面包含了流程设计器、用户管理、管理监控等功能。但在实际项目里,我一般不建议直接把官方UI作为生产系统的流程设计器,原因很简单:它是单体应用,打包重、风格老、权限模型和你自己的业务系统对不上,强行嵌入会引入一大堆维护负担。

比较务实的路径有三条:一是本地开发用官方flowable-ui,把流程模型画好后导出BPMN XML,再放到你的业务项目里做自动部署;二是前端团队自己基于bpmn-js封装一个流程设计器,后端提供Flowable Modeler的存取接口,这在生产环境更可控;三是直接使用JeecgBoot这类低代码平台的流程设计模块,它们的UI已经和业务权限做过适配,比裸集成官方UI省事。

无论选哪条,都要注意一个细节:Flowable Modeler保存的BPMN XML里会有大量diagram样式信息,如果你的流程节点变了,这些diagram信息不会自动清理干净,流程图显示时经常出现线叠线、节点偏移。我以前在这上面吃过亏,后来习惯在保存模型时用Flowable的BpmnModelParser重新解析一遍,再统一生成diagram信息,而不是直接信任前端传回的XML。

3.3 JeecgBoot集成Flowable:不是换个依赖就能跑

现在很多项目是基于JeecgBoot这类快速开发平台做的,它的老版本里默认集成的是Activiti,但网上越来越多的教程在讲“JeecgBoot集成Flowable”,说明行业风向在变。如果你需要自己动手做集成,我提醒几个真坑。第一,用户体系对接。流程引擎里的任务必须要有“人”去认领,但引擎不认你的sys_user,它识别的是ACT_ID_表或者Flowable自己的用户。常见做法是在应用启动时同步一批业务用户,或者在任务查询入口做一个自定义的UserId映射。这一步没做好的话,任务列表里永远看不到当前登录人的待办。

第二,组织机构和数据权限。Java应用的工作流引擎本身不关心你的部门数据权限,但审批流里几乎每个节点都要按部门、角色、岗位去路由。JeecgBoot有自己的部门表,Flowable则用组和角色来做分配,中间需要一个转换层。我见过一个项目因为没有做这个转换,导致流程发起人提交后,审批人列表里出现了所有部门的同名人,权限直接炸了。第三,事务边界。JeecgBoot里很多Service方法默认带事务,而Flowable的流程节点操作涉及引擎内部的事务管理。如果你在自己Service里叠加了流程启动、任务完成、消息通知等多个操作,稍不注意就会触发事务嵌套问题。建议把“流程操作”和“业务操作”拆开编排,要么用Spring事务同步器,要么先做业务再异步触发流程流转,别指望引擎能自动帮你处理好所有边界。

4. 不同业务场景下最实用的选型建议

4.1 标准审批流:稳定压倒一切

如果业务就是大批量的请假、报销、用印、合同审批,节点少、岗位固定、流程不会三天两头改,那么Activiti和Flowable都能很好满足,选哪个都不会错。这个时候真正应该比较的不是引擎本身,而是你们团队的熟练度和现有系统耦合。老项目用了Activiti,不要因为一些小功能差异去迁移,迁移带来的风险远大于收益。

如果是从零开始,我依然会建议选Flowable。原因不是Activiti跑不动,而是Flowable在“标准审批流之外的意外需求”上处理得更好。比如过段时间业务方突然提出要加一个会签、要按发起部门路由、要能从任一步骤退回到特定节点,Flowable的历史数据和状态跳转API会帮你省不少代码。你可以把它理解成买保险,平时看着没差距,真出险的时候才知道值不值。

4.2 复杂动态流程:流程追回、驳回和自由路由

复杂流程往往意味着高变化,高频操作包括流程追回、驳回上一节点、退回发起人、任意跳转、加签转办。前面说了,这些功能引擎都不会直接给你,但选一个状态控制好、历史数据全的引擎能明显降低自研成本。我自己的经验是,在设计复杂流程时不要把太多判断逻辑塞进BPMN的网关里,很容易变成蜘蛛网图,后期别人根本不敢改。更合适的做法是,把“退回”这类动作设计成一种服务任务,由代码去修改流程实例的活动节点,而不是靠一连串条件表达式来实现。

Flowable对运行时节点迁移的API支持比较完整,能够通过状态变更构建器获取当前活动节点、计算目标节点,然后执行迁移,操作起来比Activiti更顺滑。如果你需要支持“任意节点追回”,建议在数据库里多存一张业务自定义的流程轨迹表,把每个审批节点的处理状态、时间、意见都冗余出来。不要总是去查ACT_HI_*表,那样上线时间长了会非常吃力。运行时用Flowable的RuntimeService拿活动节点,历史用你自己的轨迹表做展示和校验,这算是最省心的组合。

4.3 遗留系统和生态捆绑:先想清楚要不要迁移

很多公司其实早就用Activiti跑着核心审批系统,这时问“要不要换成Flowable”,本质上是一个业务连续性决策,不是技术决策。除非你遇到了一个无法绕开的技术瓶颈,比如CMMN必须用、DMN必须用、性能瓶颈确确实实和引擎有关,否则我建议不要轻易迁移。开发一套新流程可以选Flowable,老流程继续维持Activiti,两个引擎短时间内并行不是大问题,前提是应用层把工作流服务接口抽象好。

生态捆绑方面,如果你已经深度使用了某个低代码平台,比如JeecgBoot,并且平台内置的流程引擎就是Activiti,那短期内跟着平台走更省力。但如果你的团队有能力做平台集成,并且希望未来流程能力更可控,集成Flowable也完全可行,毕竟社区里已经有成熟的集成案例可以参考。选型没有绝对答案,关键是明确自己最不能失去的是什么:是稳定,是功能,还是生态。

5. 常见问题与排查技巧实录

5.1 流程追回高频报错:OptimisticLockingException

流程追回这个需求搜索热度很高,所以我把它放第一个说。很多团队实现追回时会遇到一个经典报错:OptimisticLockingException,日志里还会带着一句“was updated by another transaction concurrently”。这个报错的本质不是程序写错了,而是多个请求并发修改了同一条运行时数据记录,乐观锁版本号不匹配。我见过最常见的场景是:用户在前端同时点了“同意并追回”或者“撤回并重新提交”,两个请求都跑到同一个TaskService方法里。虽然操作不同,但都在改同一个ACT_RU_EXECUTION或ACT_RU_TASK记录。

解决办法不是往代码里加一遍遍重试,而是要对流程实例维度加锁。简单粗暴的方案是把“流程实例ID”作为分布式锁的Key,在Redis或者数据库里加一把业务锁,锁到整个追回操作执行完再释放,这比依赖引擎乐观锁靠谱得多。另外,追回操作一般涉及流程节点跳转,要先把当前活动节点找出来。这里建议优先用HistoryService查最新一次的任务历史,不要直接用RuntimeService里的当前任务列表,因为你追回的对象可能已经不处于“待办”状态,运行时表里未必还能查到记录。

5.2 从Activiti迁移到Flowable:版本对应和迁移步骤

不换引擎则已,一旦确定要迁移,我按经验把整个流程拆成六步,供大家参考。第一步,盘点现有流程定义,把BPMN XML和相关业务表单字段列出来;第二步,把应用里的org.activiti所有import批量替换成org.flowable,同时修改配置文件中的引擎属性;第三步,统一数据库连接配置,让Flowable先识别现有表结构,如果有自动升级能力就在测试环境跑一遍,但绝对不要在测试环境直接跑生产历史库;第四步,重写监听器、事件处理器和命令拦截器,因为这部分接口变化很大;第五步,把全部流程定义部署一遍,逐个跑一遍完整性测试,重点看回退、追回、会签这些高级操作;第六步,并行验证一段时间,确认两边历史数据和统计报表一致,再切流量。

这个过程中最花时间的是第五步。很多人以为变更包名就能搞定,但实际系统里往往有大量跟Activiti内部类耦合的业务代码,比如调用了CommandExecutor、SessionFactory,甚至直接操作了数据表。迁移不是换引擎,是还债。

5.3 历史数据膨胀、僵尸流程和慢查询怎么排查

历史数据膨胀是工作流系统长期运行的必经问题。我建议从第一天就按定时任务来归档数据,归档时不要只删ACT_HI_*,还要把业务流程轨迹表、附件表这些一起评估,否则恢复某个历史阶段的数据时会有缺漏。僵尸流程通常表现为流程实例停留在等待状态,既没有报错也没有向前推进。排查顺序是:先看ACT_RU_EXECUTION里有没有长时间停留在等待节点上的记录,再看FLW或ACT_RU_JOB里有没有连续失败的定时作业,然后看异步执行器是否被关闭了。如果异步执行器关了,很多定时边界事件永远不会触发,外部表现就是流程卡死。这个问题我遇到不止一次,都是因为在配置里图省事把async-executor-activate设成了false,后来忘了在需要时重新打开。

如果查询越来越慢,优先检查索引而不是盲目加服务器配置。ACT_HI_TASKINST的END_TIME_、ASSIGNEE_,ACT_RU_TASK的CREATE_TIME_、TASK_DEF_KEY_,这些字段在业务查询里出现频率最高,把它们按实际SQL建好索引,往往比改一堆配置更见效。

我个人这几年做下来,最深的体会是:选型时别把“引擎能不能追回”当成第一问题,应该先问自己“业务对流程状态的掌控要求有多高”。很多项目选错,不是因为引擎差,而是没梳理清楚业务的异常分支。如果一开始就把驳回、追回、会签这些高频需求放进设计和测试范围,不管最后选Activiti还是Flowable,都不会太难受。希望大家在选型前多跑几个Demo,多压一次数据库,少一点口头争论,多一点实测数据。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询