Activiti还是Flowable?工作流引擎选型与落地避坑指南
做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案例管理较弱较成熟非结构化流程选FlowableDMN决策表较弱较成熟有规则引擎需求选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快速集成Flowable5分钟搭一个最小可用流程先从最繁琐的Spring Boot集成说起。很多同学第一次接触Flowable会去搜“Flowable详细使用教程”看到一大堆模块就发怵。其实最简单的情况下只需要一个依赖加一点配置就能启动。dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter/artifactId version6.8.0/version /dependency如果你本地是MySQL用下面这份配置就能把引擎跑起来。spring: datasource: url: jdbc:mysql://localhost:3306/flowable_demo?useUnicodetruecharacterEncodingutf8nullCatalogMeansCurrenttrue 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-levelFlowable支持四个历史级别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多压一次数据库少一点口头争论多一点实测数据。