拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Spring Boot 2.6.13 + MySQL 8 + Flowable 6.8.1 集成部署与避坑实战

简介面向需要落地Spring Boot 2.6.13、MySQL 8与Flowable 6.8.1集成项目的中高级Java开发者这套工程以可运行项目为载体解决工作流引擎接入、流程定义与数据持久化之间的环境配置痛点。压缩包共29个文件以8个xml流程/配置描述、7个java业务代码、2个yml应用配置、5个class编译产物为核心并内置mysql-installer-community-8.0.41.0.msi安装程序整体约382.9MB既便于对照工程结构也能快速搭建本地环境。已有108人学习下载。借助该包可省去单独下载配置MySQL的步骤快速体验Flowable基于BPMN 2.0的流程建模与任务管理同时参考Spring Boot自动装配、REST服务封装及ORM数据交互写法适合作为企业级工作流项目的起步模板或教学案例也可迁移关键配置至自身项目减少环境不一致带来的排错成本。1. 这套组合包解决什么问题,谁该照着做Spring Boot 2.6.13 MySQL 8 Flowable 6.8.1,外加强行塞进项目包里的 MySQL 8 安装程序,说到底就是一类交付场景的答案:业务系统要带工作流,客户现场是内网,机器上没装数据库,还得让流程引擎一次跑稳。做 OA 审批、工单流转、合同会签这类项目的团队,最终选型基本都会落到这个组合上。反直觉的一点是:Flowable 6.8.1 对 Spring Boot 2.6.x 的适配比想象中顺,真正的高发坑几乎全在 MySQL 8 的认证插件、时区和排序规则上。下面按版本选型、数据源接入、Flowable 引擎配置、数据库落地、排障、验证进阶这条线完整走一遍。2. Spring Boot 2.6.13 接 MySQL 8:从版本锁定到连接池参数2.1 为什么钉死 2.6.13 和 MySQL 8:版本契约比功能更重要Spring Boot 2.6.13 是 2.6 这条分支的最后一个修复版本,拿它做基线意味着整个 2.6 系列的已知问题都在这个版本上收口了。Flowable 6.8.1 的 starter 内部依赖声明是基于 Spring Boot 2.6.x 管理的,两者放一起编译期不会打架。MySQL 8 这边,Connector/J 8.0.x 从 8.0.13 起完整支持 caching_sha2_password 认证,而 Spring Boot 2.6.13 的依赖管理正好落在 8.0.x 区间,所以不用手动指定 mysql-connector-j 的版本号。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.6.13/version relativePath/ /parent properties java.version1.8/java.version flowable.version6.8.1/flowable.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jdbc/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency /dependencies这里有个大多数人会忽略的点:mysql-connector-java 没有写 version,是因为 Boot 2.6.13 的 parent 已经把它锁在 8.0.x 了,再写反而可能引入你自己没测过的小版本。scope 用 runtime 是惯例,编译期用不到 JDBC 类。Java 8 是这套组合里兼容性最好的,后面换成 Java 11 也可以跑,但没必要在交付时给自己加变量。如果你在 pom 里看到 mysql-connector-j 和 mysql-connector-java 两个坐标同时存在,那是从 Boot 2.7.x 的项目里拷过来的。2.6.13 只认后者,两个都写会拉进两个驱动包,启动时 SPI 探测可能拿到重复驱动,这种问题排查起来非常玄学。2.2 数据源配置:时区、SSL、公钥拉取三个参数必须一起设application.yml 里 90% 的连接问题都出在 JDBC URL 的参数组合上。MySQL 8 默认认证插件是 caching_sha2_password,非 SSL 连接下驱动需要从服务端拉取 RSA 公钥完成密码置换,allowPublicKeyRetrieval 默认是 false;再加上国内服务器默认时区不是 Asia/Shanghai,serverTimezone 不写就会取 JVM 时区,两边对不上直接报通信异常。这三个参数要一次性写对。spring: datasource: url: jdbc:mysql://127.0.0.1:3306/biz_flow?useSSLfalseuseUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: flow_user password: ${DB_PASSWORD:flow_pass} hikari: pool-name: BizHikariCP minimum-idle: 5 maximum-pool-size: 20 connection-timeout: 30000 idle-timeout: 600000 validation-timeout: 3000 connection-test-query: SELECT 1几个关键参数的语义拆开说。useSSLfalse 是为了省掉 SSL 握手开销,内网环境没有中间人风险,可以关;如果客户要求加密链路,就得改成 useSSLtruesslModeREQUIRED,并保证两端信任链一致,否则会在建立连接时抛 SSL 握手异常。serverTimezoneAsia/Shanghai 写死在 URL 里,比在 my.cnf 配 default-time-zone 更稳,因为应用和数据库可能在两台机器上。characterEncodingUTF-8 只负责连接层的字符集协商,库里表实际是不是 utf8mb4 取决于建库语句,这一点到第 4 章会专门处理。HikariCP 是 Spring Boot 2.6 默认连接池,不需要额外引依赖。maximum-pool-size 设 20 对工作流系统是合理值,Flowable 异步执行器会占线程,同时业务线程也在查 ACT_ 表,池太小会在流程发起时出现获取连接超时;minimum-idle 保留 5 个常驻连接,避免突发流量时冷启动。validation-timeout 必须小于 connection-timeout,否则 Hikari 会在校验失败时多等一个无效周期,报错要晚三秒。2.3 多环境配置与密码脱敏:交付给客户时不留明文工作流引擎一旦接进来,数据库密码就不是开发人员的本地密码了。交付现场往往是客户运维来启动应用,他们能看到 application.yml,明文密码等于把库敞开。常见做法是拆三个文件:application.yml 只放公共项,application-dev.yml 和 application-prod.yml 按环境覆盖。生产环境的密码用环境变量注入。spring: profiles: active: ${SPRING_PROFILES_ACTIVE:dev} datasource: password: ${DB_PASSWORD}# application-prod.yml spring: datasource: url: jdbc:mysql://${DB_HOST:127.0.0.1}:3306/biz_flow?useSSLfalseuseUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: ${DB_USER:flow_user}启动命令里带上环境变量即可:DB_PASSWORDxxx SPRING_PROFILES_ACTIVEprod java -jar app.jar。注意SPRING_PROFILES_ACTIVE是 Spring Boot 内置占位符,不是随便取的全局变量名。这里不要动 driver-class-name,Spring Boot 2.6 能从 URL 自动推导 MySQL 驱动;只有当启动日志里明确出现 No suitable driver 时才补driver-class-name: com.mysql.cj.jdbc.Driver,逗号分隔的 JDBC 4 自动探测在个别 Linux 发行版上确实会失败,这时补上反而省排查时间。3. 接入 Flowable 6.8.1:依赖仲裁、引擎配置与 CommandExecutor 改造3.1 flowable-spring-boot-starter-process 的连带依赖,别让 MyBatis 打架Flowable 6.8.1 的 starter 会连带引入 flowable-engine、flowable-spring、mybatis、mybatis-spring 一套东西。它内部会构建独立的 SqlSessionFactory,和业务项目里你自己配的 MyBatis、MyBatis-Plus 不共用工厂,理论上互不干扰。实际翻车点在于:业务代码里如果用了 mybatis-plus-boot-starter,它和你自己数据源绑定,而 Flowable 的 MyBatis 是挂在它的 ProcessEngineConfiguration 底下的,两边扫到同一个 mapper 接口时就可能报重复绑定。规避办法是业务 mapper 包名与 Flowable 的仓库路径严格分开,并且不要把 Flowable 的 mapper 接口让业务 SqlSessionFactory 去扫描。dependency groupIdorg.flowable/groupId artifactIdflowable-spring-boot-starter-process/artifactId version6.8.1/version /dependency这个依赖只在需要流程引擎时报,不需要关心它是怎么把引擎装配进 Spring 容器的。需要 REST API 就另加 flowable-spring-boot-starter-rest,需要表单引擎加 flowable-spring-boot-starter-form,别一上来全家桶,引擎启动要初始化的服务多,交付现场排错成本高。版本号直接写 6.8.1,不要写成 6.8.1-SNAPSHOT 之类的中间版本。3.2 引擎核心配置:自动建表、异步执行器与历史级别Flowable 的配置前缀是 spring.flowable,这点容易和 spring.datasource 混。首次启动时引擎要建 ACT_ 开头的几十张表,database-schema-update 必须为 true;流程上线后建议改 false,避免每次启动都去比对表结构。异步执行器这块要单独说:async-executor-activate 默认 false,只有你用了定时器边界事件、会签超时提醒或异步延续时才开。开 true 后引擎会起一组线程扫 ACT_RU_JOB 表,对 MySQL 8 的锁机制有额外要求,第 5 章会给出具体冲突。spring: flowable: database-schema-update: true db-history-used: true history-level: full async-executor-activate: true async-executor-core-pool-size: 8 async-executor-max-pool-size: 16 async-executor-queue-capacity: 100 deployment-mode: default process-definition-location-prefix: classpath*:/processes/history-level 有 none, activity, audit, full 四档。审计和合规场景必须 full,它会把流程实例、活动、变量、任务的完整历史都写进 ACT_HI_ 表;一般内部 OA 用 audit 就够,能少一半历史表数据量。db-history-used 设 true 表示走历史表而不是内存历史。这组参数要在交付前定好,中途降 history-level 会导致历史数据断层,表里有点但查不全,这种问题客户不会容忍。3.3 自定义 CommandExecutor:慢命令拦截与租户隔离的入口热搜词里 flowable commandexecutor 被反复提到,因为它确实是引擎执行的咽喉。Flowable 里每个对引擎的操作,比如 startProcessInstanceByKey、complete,都会包装成一个 Command 丢给 CommandExecutor 执行。执行链路是 CommandExecutor - CommandInterceptor 链 - CommandContext。在这条链上插入自定义拦截器,就能拿到每个命令的耗时、入参和异常。Configuration public class FlowableCommandConfig implements ProcessEngineConfigurationConfigurer { Override public void configure(AbstractEngineConfiguration engineConfiguration) { ListCommandInterceptor interceptors engineConfiguration.getCustomPreCommandInterceptors(); if (interceptors null) { interceptors new ArrayList(); } interceptors.add(new CommandCostInterceptor()); engineConfiguration.setCustomPreCommandInterceptors(interceptors); } public static class CommandCostInterceptor extends AbstractCommandInterceptor { private static final Logger log LoggerFactory.getLogger(CommandCostInterceptor.class); Override public T T execute(CommandConfig config, CommandT command) { long start System.currentTimeMillis(); try { return next.execute(config, command); } finally { long cost System.currentTimeMillis() - start; if (cost 500) { log.warn(flowable slow command [{}] cost [{}ms], command.getClass().getSimpleName(), cost); } } } } }核心逻辑在 finally 块里算耗时,命令执行超过 500ms 就记慢命令。这个阈值按业务调,审批流里一个 complete 命令通常 50ms 以内,超过 500ms 说明要么连接池不够,要么 ACT_RU_TASK 的索引失效。利用同样的拦截点,可以在 next.execute 前后往 CommandContext 塞租户 ID,实现多租户流程隔离,Flowable 的 tenantId 由 TenantHolder 静态变量承载,在拦截器里赋值、在业务代码里读取。实现时要实现 ProcessEngineConfigurationConfigurer 而不是直接改 ProcessEngine Bean,原因是这个 Configurer 在引擎构建前回调,配置对默认值和已有的 Bean 都生效;等 ProcessEngine 暴露出来再 set 拦截器,引擎已经初始化完,拦截器进不去。AbstractCommandInterceptor 的 next 字段由引擎在链路组装时注入,自己 new 一个不会有行为。3.4 流程定义自动部署:processes 目录的约定与版本管理Flowable 启动时会扫 classpath 下的 processes 目录,把 .bpmn20.xml 和 .bpmn 文件自动部署成流程定义。同一流程 key 多次部署不会冲突,引擎按版本递增,ACT_RE_PROCDEF 里同一个 KEY_ 会有多条记录,发起流程时默认拿最高版本。开发期这个特性很方便,交付后就要小心:客户现场重新部署 jar 包,流程定义版本又涨一版,老流程实例还在跑旧版本,两边行为可能不一致。curl -X POST http://localhost:8080/process-api/runtime/process-instances \ -H Content-Type: application/json \ -d {processDefinitionKey:leave_approve}这个接口来自 flowable-spring-boot-starter-rest,返回 201 并带 processInstanceId 即部署链路通了。注意如果地址返回 404,先确认依赖里加了 starter-rest,而不是只看 flowable-spring-boot-starter-process,后者不开放 REST 端点。deployment-mode 保持 default 就好,即扫描整个 processes 目录;改成 single-resource 只会部署你指定的那一个文件,适合客户现场只想单独更新某条流程的场景。4. 自带 MySQL 8 安装程序:离线交付时的数据库落地方案4.1 为什么把 MySQL 装进项目包,而不是让客户自己装标题里「自带 mysql8 安装程序」这个细节,本质是私有化交付的数据库方案。客户现场往往不满足三个条件:不通外网、机器上没有 MySQL、运维不熟悉数据库安装。与其让客户去官网找下载链接并且对着安装教程操作,不如把安装介质、初始化脚本、账号脚本、校验脚本一起放进部署包。这样版本由你锁定,字符集和排序规则由你初始化,应用连库的参数和库的实际配置严格对应,省掉一堆「我按网上教程装的,为什么连不上」的售后问题。常见做法是部署包里有 mysql 的 linux 发行版介质(一般是 tar.xz 格式,也可以按操作系统换成 rpm,脚本逻辑不变),和 init_db.sql。介质文件名在交付时和脚本里的通配符对应即可,不用写死在脚本里。整个过程四条命令:解压、建目录、初始化数据目录、启动并执行初始化 SQL。4.2 install_mysql8.sh:四步装完一个能用的 MySQL 8#!/bin/bash # install_mysql8.sh - 离线安装 MySQL 8 并初始化业务库 set -euo pipefail MYSQL_HOME/usr/local/mysql DATA_DIR/data/mysql8 PORT3306 SOCKET/tmp/mysql.sock echo [1/4] 解压介质 tar -xf ./mysql-8*.tar.xz -C /usr/local mv /usr/local/mysql-8* ${MYSQL_HOME} echo [2/4] 创建运行用户与数据目录 id mysql || useradd -r -s /sbin/nologin mysql mkdir -p ${DATA_DIR} chown -R mysql:mysql ${MYSQL_HOME} ${DATA_DIR} echo [3/4] 初始化数据目录 ${MYSQL_HOME}/bin/mysqld --initialize-insecure \ --basedir${MYSQL_HOME} \ --datadir${DATA_DIR} \ --usermysql echo [4/4] 启动 mysqld_safe ${MYSQL_HOME}/bin/mysqld_safe --basedir${MYSQL_HOME} \ --datadir${DATA_DIR} \ --socket${SOCKET} \ --port${PORT} 脚本里三个关键点。set -euo pipefail让每一步失败立即退出,部署时不会出现脚本显示成功但 MySQL 实际没起来的假象。--initialize-insecure生成空密码 root 账号,方便脚本后续接管执行建库语句;生产环境想更严格,就改用--initialize,密码会随机生成并打到错误日志里,再由脚本去取。mysqld_safe放后台运行,交付脚本最好在末尾轮询 mysqladmin ping 确认连接可用,再提示部署完成,不然进程刚起来脚本就结束,客户端连接时会撞上 socket 还没创建。echo 等待 MySQL 启动... for i in $(seq 1 30); do ${MYSQL_HOME}/bin/mysqladmin -uroot -h127.0.0.1 -P3306 ping /dev/null 21 break sleep 1 done ${MYSQL_HOME}/bin/mysql -uroot -h127.0.0.1 -P3306 ./init_db.sql这里特意用了-h127.0.0.1 -P3306走 TCP,而不是默认 socket,原因:MySQL 客户端默认连 /tmp/mysql.sock,如果 my.cnf 把 socket 路径改了,命令行直接报 error 2002,而这句脚本会因为 ping 失败循环 30 秒才暴露问题。走 TCP 能绕开 socket 路径这个变量,让脚本在交付现场少一个失败入口。4.3 init_db.sql:字符集、账号权限与两个 host 的坑数据库初始化脚本是这套组合里最关键的一份 SQL。MySQL 8 默认字符集虽然是 utf8mb4,但排序规则默认是 utf8mb4_0900_ai_ci,如果业务代码里用了大小写敏感的查询,或者后续要导入 5.7 时代的老库,这个排序规则会有兼容问题。交付场景统一指定 utf8mb4 和 utf8mb4_general_ci,兼容性最稳。CREATE DATABASE IF NOT EXISTS biz_flow DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; CREATE USER IF NOT EXISTS flow_userlocalhost IDENTIFIED BY flow_pass; CREATE USER IF NOT EXISTS flow_user127.0.0.1 IDENTIFIED BY flow_pass; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES ON biz_flow.* TO flow_userlocalhost; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES ON biz_flow.* TO flow_user127.0.0.1; FLUSH PRIVILEGES;账号为什么要给两个 host:Connector/J 走 TCP 时,MySQL 端看到的主机名取决于服务端反向解析,可能是 localhost 也可能是 127.0.0.1。只建一个 host 的账号,会出现「用户名密码正确,但 Access denied」的怪事,这是 MySQL 账号匹配 host 的机制决定的,和密码无关。权限里必须包含 CREATE 和 ALTER,Flowable 首次启动要建 ACT_ 表、后续版本升级要改表;INDEX 用于引擎自动补索引;DROP 留给引擎在版本变更时清理废弃表。业务账号不要给 ALL PRIVILEGES,避免一个应用账号能动整个实例。4.4 Spring Boot 连接自装 MySQL 8 的参数对照自装 MySQL 8 的实例,默认就是 caching_sha2_password 加 utf8mb4,所以应用连接时 JDBC URL 里要与之对应。参数推荐值不设或设错的表现allowPublicKeyRetrievaltrueNon-JRAS server config 或 Public Key Retrieval is not allowedserverTimezoneAsia/Shanghai服务端与 JVM 时区不一致,时间字段错 8 小时characterEncodingUTF-8中文乱码,流程名称/审批意见写不进库useSSLfalse(内网);truesslModeREQUIRED(加密要求)默认 false 不报错;设 true 但无证书则握手失败rewriteBatchedStatementstrueFlowable 批量插入历史数据变慢,大批量流程发起时明显其中 rewriteBatchedStatements 容易漏。Flowable 在启动和运行时批量写 ACT_HI_ 表,连接参数不开启这个选项,MySQL 会逐条执行,历史数据量大时 complete 任务响应明显变慢。它是连接层参数,加在 URL 里即可,不需要改引擎配置。5. 避坑记录:这套组合同样容易翻车的问题与排查路径5.1 Public Key Retrieval is not allowed:认证插件与连接参数不匹配现象:Spring Boot 启动时数据源初始化失败,或第一个请求打库报 java.sql.SQLNonTransientConnectionException,提示 Public Key Retrieval is not allowed。 原因:MySQL 8 默认 caching_sha2_password,Connector/J 8.0.x 在非 SSL 模式下需要向服务端请求 RSA 公钥做密码传输,allowPublicKeyRetrieval 默认 false,驱动拒绝自动拉取。 解决:JDBC URL 补allowPublicKeyRetrievaltrueuseSSLfalse。如果客户安全要求必须走 SSL,则保留 useSSLtrue 并配置 sslModeREQUIRED,此时驱动不再走公钥拉取路径,这个报错也会消失。第 2 章已经把这组参数写进了示例里,直接抄即可。排查时可以先用命令行客户端mysql -uflow_user -pflow_pass -h127.0.0.1 -P3306验证账号密码确实没问题,再回来看 URL 参数,多数情况是密码没错、参数没带。5.2 error 2002 (HY000):socket 路径不一致,客户端和服务端各说各话现象:在 Linux 上用mysql命令连接报ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock,但 Spring Boot 应用连 127.0.0.1:3306 却能通。 原因:mysqld_safe 启动时实际监听的是自定义 socket 路径(比如 /var/lib/mysql/mysql.sock),mysql 客户端默认找 /tmp/mysql.sock;两边路径不一致,客户端自然连不上。 解决:最省事的方式是统一走 TCP——mysql -uroot -h127.0.0.1 -P3306 -p,绕开 socket 文件;把 socket 路径写进 my.cnf 的 [client] 段,也可以根治:socket/tmp/mysql.sock。第 4 章的启动脚本里特意把 --socket 传成了 /tmp/mysql.sock,就是为了让客户端默认路径和服务端一致。如果你的安装程序改了 socket,记得把 [client] 和 [mysqld] 两段一起改。5.3 Flowable 异步执行器在 MySQL 8 下任务积压,ACT_RU_JOB 表锁竞争现象:开启 async-executor-activate 后,ACT_RU_JOB 里定时任务越积越多,日志频繁出现 Deadlock found when trying to get lock,流程的定时边界事件不触发。 原因:异步执行器的多线程同时扫 ACT_RU_JOB,MySQL 8 默认隔离级别 REPEATABLE_READ 下,多个连接对同一行 UPDATE 产生锁等待,超过 innodb_lock_wait_timeout 后回滚报死锁。 解决:调小执行器线程池,减少并发抢锁。async-executor-core-pool-size设 4~8,max-pool-size设 8~16,并给 URL 加lockWaitTimeout不是标准参数,正确做法是在 MySQL 端适当调大innodb_lock_wait_timeout到 50 秒。同时检查业务侧是否有流程实例长期挂在定时器上,异常的 ACT_RU_JOB 会在每次扫描时被反复锁定。更彻底的办法是把定时任务改成单独模块处理,引擎只负责生成待办,这个方向放在第 6 章展开。5.4 Specified key was too long:utf8 老库碰上 Flowable 建表现象:Flowable 首次启动建表失败,日志报 Specified key was too long; max key length is 3072 bytes,建表停在某张 ACT_ 表上。 原因:库或表字符集还是 utf8,utf8 一个字符占 3 字节,Flowable 某些索引设计的字段长度在 utf8 下超了 InnoDB 的索引上限。常见于从 MySQL 5.7 项目启来的库,建库时没显式指定字符集,继承的还是老配置。 解决:第 4 章的建库语句已经统一了 utf8mb4,一字符 4 字节,索引字节数会更紧张,所以更关键的是 Flowable 的建表语句是按 InnoDB 3072 字节上限设计的,在 utf8mb4 下没问题;真正触发这个报错的是库字符集混乱——旧表是 utf8,新表是 utf8mb4,引擎又在同一个库里建表。清理方案:新建业务库并按第 4 章规范指定字符集,别在老库上直接跑 Flowable。顺手检查一下 MySQL 8 的 lower_case_table_names 参数,这个参数只能在初始化时定,中途改会导致数据字典不一致,MySQL 直接拒绝启动,交付时别为了迁旧库去动它。5.5 Spring Boot 版本太高,Flowable 6.8.1 直接顶不住现象:把项目从 Spring Boot 2.6.13 升到 2.7 或 3.0,启动时报 NoSuchMethodError、ClassNotFoundException,多发生在 javax到 jakarta 命名空间相关的类上。 原因:Flowable 6.8.1 内部依赖声明基于 Boot 2.6.x,Spring Boot 3.0 全面切换 jakarta 命名空间,Flowable 6.8.1 还没迁移,运行时自然找不到类。 解决:遵守整套技术栈的版本契约,别单独升 Boot 版本。要升 Boot 3,就得连同 Flowable 一起升到 7.x,同时处理 jakarta 迁移、配置项变更等一系列问题。这类问题在热搜词「springboot版本太高」里确实常见,但这里的教训是:工作流引擎是个深度依赖 Spring 生命周期管理的组件,版本联动比普通业务库敏感得多。升级前先看 Flowable 官方 release notes 对 Spring Boot 的适配区间,而不是看它编译能不能过。6. 验证与进阶:从跑通第一条流程到生产可用6.1 用 REST API 或单元测试验证引擎链路Flowable 提供 flowable-spring-boot-starter-rest,但我更喜欢在交付前写一个集成测试,直接调用引擎服务的 API,避免依赖 REST 层把问题包住。核心验证三步:部署流程定义、启动流程实例、完成任务节点。SpringBootTest class FlowableSmokeTest { Autowired private RepositoryService repositoryService; Autowired private RuntimeService runtimeService; Autowired private TaskService taskService; Test void deployAndStart() { repositoryService.createDeployment() .addClasspathResource(processes/leave_approve.bpmn20.xml) .name(冒烟测试) .deploy(); ProcessInstance instance runtimeService .startProcessInstanceByKey(leave_approve); Task task taskService.createTaskQuery() .processInstanceId(instance.getId()) .singleResult(); assertNotNull(task); } }这个测试覆盖了引擎启动、BPMN 解析、流程实例创建、任务查询四条链路。跑完后再用SELECT KEY_, VERSION_, RESOURCE_NAME_ FROM ACT_RE_PROCDEF看一眼版本号,确认每部署一次 version 递增。历史数据是否正确,查 ACT_HI_PROCINST 的 START_TIME_ 和 END_TIME_ 是否按预期写入。6.2 进阶方向:异步执行器与消息队列解耦Flowable 6.8.1 的异步执行器在 MySQL 8 上锁竞争明显,生产环境我建议把「需要可靠触发的定时事件」从引擎内搬出去。做法是关掉 async-executor-activate,在业务侧用消息队列监听待办超时,触发时调用 processInstance 的 messageEventReceived 或 signalEventReceived。这样 ACT_RU_JOB 里只保留极少数短期任务,并在整个部署包里少一个线程池和内网数据库的博弈点。多租户隔离则利用第 3 章的 CommandInterceptor,在命令执行前绑定 TenantHolder,保证一个流程引擎撑多个业务方。6.3 一个收尾习惯我做这套组合时有个习惯:交付前先把整套部署包在干净的 CentOS 7 虚拟机上按文档跑一遍,从安装 MySQL 8 开始,到 Flowable 建表结束,全程不看屏幕。哪个环节需要人工介入,哪个参数报错,都会在这一遍暴露干净。之前就靠这个习惯避开了两次「本地能跑、现场必挂」的静默升级翻车。希望帮到你。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门