Spring Boot 4 升级别只看编译绿:Forge Admin 在 Jackson、Tomcat JSON 限流、MP 包名与 Flowable 库上踩过的坑

升级到 Spring Boot 4 的第一周,最容易被骗的是这一幕:Maven reactor 全绿,本地 clean package 也过了,结果一上联调------大整数金额或脱敏字段行为漂移、超大 JSON 没被拦住、CRUD 生成器吐出的 ServiceImpl 再次编译失败、MCP 异步重进偶发丢登录态、共享测试库被 Flowable 8 写过后再也切不回 7.x。

先说结论 :Boot 4 大量坑不在「能不能编译」,而在 默认协议换了、容器能力缩了、第三方主版本与库状态绑死了 。Forge Admin 在独立兼容分支把底座钉到 Boot 4.1.1 / Flowable 8.0.0 / Sa-Token 1.45 / MyBatis-Plus 3.5.17 / Spring AI 2.0.1 / Redisson 4.8.0,跑过 T0--T6 兼容矩阵后才合入主线。下面五条都来自真实源码与 pitfalls,按「现象 → 根因 → Forge 怎么改」写,方便你对照自己的工程做清单。

同系列上一篇写过 Flowable 缺 applicationTaskExecutor、以及 Sa-Token 旧 Redis Session 类型删不掉导致「看起来像缺租户」:传送门。本文 不再展开 那两条细节,只在文末清单留勾选项,避免重复占篇幅。

版本矩阵(先对号入座)

组件 Boot 3 基线(升级前) Forge Boot 4 目标
Spring Boot 3.5.x 4.1.1
Flowable 7.0.1 8.0.0
Sa-Token 1.38 + Boot3 starter 1.45 + sa-token-spring-boot4-starter
MyBatis-Plus 3.5.7 一带 3.5.17 (拆出 mybatis-plus-spring)
Web 常见 Undertow / starter-web spring-boot-starter-webmvc + Tomcat
JSON 单一 Jackson 2 习惯 业务 Jackson 2 兼容桥 + MCP Jackson 3

证据主提交:7ce8974ec「完成底座升级及现有功能兼容回归」(引入请求体限流 Filter、Sa-Token Servlet 注册、代码生成模板包名);合入主线:6bf663717;版本属性钉死:744d94218。兼容过程文档在仓库 code-copilot/changes/spring-boot4-t0 ... t6。


坑 1:默认 Jackson 3 会绕过你的字段加解密与大整数协议

现象:HTTP 接口路径还在,前端却发现 Long / 金额 / 脱敏字段行为与升前不一致;或者业务 HTTP 与 MCP 偶发「抢」同一个 mapper,序列化异常难以复现。

根因 :Boot 4 默认走向 Jackson 3。Forge 业务侧长期依赖 Jackson 2 上的字段级加解密(Jackson2ObjectMapperBuilderCustomizer)以及大整数、日期约定;而 MCP Java SDK 需要 tools.jackson 的 JsonMapper。两套栈如果混进同一个全局 bean,比「单纯升级 Jackson 大版本」更危险------编译期几乎看不出来。

Forge 怎么改:

  1. 业务 HTTP 显式 选择 Jackson 2(Admin / App / Flow 的 application.yml 均已落地):
yaml 复制代码
spring:
  http:
    converters:
      # 必须显式选择 Jackson 2,否则 Boot 4 默认 Jackson 3 会绕过 Forge 的字段序列化。
      preferred-json-mapper: jackson2
  jackson2:
    date-format: yyyy-MM-dd HH:mm:ss
    serialization:
      fail_on_empty_beans: false
    deserialization:
      fail_on_unknown_properties: false
  1. 流程变量同样钉死:flowable.variable-json-mapper: jackson2,避免历史 JSON 类型变量被 Jackson 3 换存储语义。
  2. 加解密继续挂在 Jackson 2 Builder:forge-starter-crypto 的 JacksonCryptoConfiguration。
  3. MCP transport 单独 注入 @Qualifier("mcpServerJsonMapper") 的 Jackson 3 JsonMapper,再用 JacksonMcpJsonMapper 包一层(见 ForgeMcpServerAutoConfiguration)。业务 ObjectMapper 与 MCP mapper 分轨。

可带走 :升级第一周先全仓 grep preferred-json-mapper;新 SDK / MCP 只用 qualifier,不要把 Jackson 3 bean 设成全局默认。pitfalls 原话大意是:Boot 4 迁移必须验证 MVC 协议,不能只看编译。


坑 2:Undertow 没了,Tomcat 的「表单上限」盖不住 JSON

现象 :你以为已经配了 server.tomcat.max-http-form-post-size=20MB,超限 JSON 却仍能打进加密过滤器或业务层;或者反过来,从 Undertow 迁到 Tomcat 后,原先「靠容器挡一把」的假设失效。

根因 :Boot 4 不再支持 Undertow 。Forge 的 forge-starter-web 改为依赖 spring-boot-starter-webmvc,注释写明:「Boot 4 要求 Servlet 6.1,使用其支持的默认 Tomcat。」 Flow 服务 application.yml 也写了:「Boot 4 不再支持 Undertow;沿用请求体限制,改用 Tomcat 的有界工作线程。」 更关键的是:Tomcat 的 max-http-form-post-size 只约束表单 ,并不覆盖任意 application/json 读流或 chunked 请求。

Forge 怎么改 :表单上限保留作一层,再加 读流计数 Filter:

  • RequestBodyLimitFilter:Content-Length 超限直接 413;否则包装 ServletInputStream,按字节累加,超限回 {"code":413,"message":"请求体超过大小限制"}。实现故意避免为了限流而一次 readAllBytes 无限缓存。
  • RequestBodyLimitAutoConfiguration:默认取 forge.web.max-body-size / FORGE_MAX_HTTP_POST_SIZE(20MB),Filter 顺序放在加密过滤器读取原始正文之前。

路径:forge-starter-web/.../RequestBodyLimitFilter.java,随 commit 7ce8974ec 进入兼容分支并合入主线。

可带走:Boot 4 + Tomcat 项目,把「JSON 体上限」当成独立安全需求;只配 form-post-size 等于裸奔一半。


坑 3:MyBatis-Plus ServiceImpl 搬家了,生成器不改会持续产废代码

现象:手改的业务类终于编译过了,低代码 / CRUD 生成器再点一次,「又」冒出找不到的 import;或半个仓库还在旧包名,半个仓库在新包名。

根因 :MP 3.5.17 把 Spring 集成拆到独立模块 mybatis-plus-spring。IService / ServiceImpl 从

com.baomidou.mybatisplus.extension.service.impl

迁到

com.baomidou.mybatisplus.spring.service.impl。

只改手写类、不改 Velocity 模板,等于给未来每一次「生成」埋雷。

Forge 怎么改:

  • 生产代码与模板同步:templates/vm/serviceImpl.java.vm、service.java.vm 已改为新 import(同属 7ce8974ec)。
  • BOM 显式管理 mybatis-plus-spring、mybatis-plus-spring-boot4-starter,并继续钉 mybatis-plus-jsqlparser-4.9------数据权限 SQL 协议不跟这次一起改,降低升级面。

可带走 :升级 MyBatis-Plus 时,把「生成器模板」写进 PR 检查清单;只 sed 手写 Java 不够。


坑 4:Sa-Token 上下文只挂 REQUEST,ASYNC / ERROR 重进会丢登录态

现象:同步 Controller 一切正常;MCP Streamable HTTP、异步重新分派或 ERROR 转发后,偶发「未登录 / 上下文空」。有人会先去改 CORS 或租户拦截器,越改越远。

根因(请务必与系列上文区分) :这里不是 Redis 里旧 SaSessionForJacksonCustomized 反序列化失败(那篇已写过),而是 Servlet 调度类型 问题。Sa-Token 1.45 使用 ThreadLocal ModelBox;若 Filter 只覆盖 REQUEST,ASYNC / ERROR 重进时上下文不会从已结束的请求线程自动继承。

Forge 怎么改 :显式注册上游同一个 SaTokenContextFilterForJakartaServlet 实例,避免 Boot 再自动注册一份、也避免自己再维护第二套认证实现:

java 复制代码
registration.setAsyncSupported(true);
registration.setDispatcherTypes(
    DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);

类:SaTokenServletContextConfiguration(forge-starter-auth)。类注释原话:「Servlet 异步重新分派也必须建立 Sa-Token 上下文,不能依赖已结束的请求线程。」

可带走 :升到 sa-token-spring-boot4-starter 后,用一条真实 ASYNC / MCP 路径回归鉴权;只测同步接口会漏。


坑 5:Flowable 8 动过的库,不能「改回版本号」假装还是 7.x

现象 :共享测试库先被 Boot 4 / Flowable 8.0.0 启动写过,再切回仓库里的 Flowable 7.0.1 启动 flow-server,会连环失败:

  1. Could not update Flowable database schema: unknown version from database: '8.0.0.0'
  2. 只把 act_ge_property / act_id_property 改回 7.0.1.1 后,又报 Liquibase:Table 'flw_event_deployment' already exists(以及 App / CMMN / DMN 同类问题)

根因 :引擎主版本与 库内 schema 版本标记 + Liquibase changelog 是一套的。半升级 / 半回退会留下「有表、无 changelog」。这条写在 code-copilot/memory/pitfalls/flow.md(发现日期 2026-10-13),是实踩记录,不是推演。

Forge 原则:

  • 代码与库同主版本:要上 Boot4 + Flowable8,就 Admin / Flow / 依赖一起升,不要只升一半去蹭共享库。
  • 误污染且仍要跑 7.x 的测试库 :恢复 7.x 版本键,并删除 changelog 已乱的 Event Registry / App / CMMN / DMN 引擎表;保留 流程核心 act_re_/ru_/hi_ 与业务侧 sys_flow_*(生产库勿照抄「清空」动作,细节以 pitfalls 为准)。
  • 变量协议:flowable.variable-json-mapper: jackson2,与坑 1 同一套「业务 JSON 语义不变」。

合并分支常炸的附加项 :Boot4 兼容分支合入 main 后,曾同时存在两个 V1.0.218__*.sql,Flyway 直接无法启动(pitfalls db-flyway.md,2026-10-16)。合并后、提交前先查重:

bash 复制代码
ls forge-server/db/migration/V*.sql | sed 's/__.*//' | sort | uniq -d

已执行的那份文件名与内容都不动;另一方 git mv 到当前最大版本号 + 1。Admin 默认:

yaml 复制代码
spring.flyway.locations: ${FORGE_FLYWAY_LOCATIONS:classpath:db/migration}
spring.flyway.fail-on-missing-locations: true

避免生产 JAR 正确、却去扫服务器工作目录里残留的旧 db/migration。


建议升级顺序(Forge 实操摘要)

结合 T0 探针 → T1 底座 → 合入主线的经验,建议读者按这个顺序做,而不是「一次性改 BOM 再祈祷」:

  1. 先隔离验证:用独立 profile / 探针工程确认 Flowable 8、Sa-Token Boot4 starter、目标 AI BOM 能否装配;保留负面结果,不要为了绿灯降级到未验证的 milestone。
  2. 再改底座 POM :统一 Boot / MP / Sa-Token / Webmvc;同时改生成器模板与 preferred-json-mapper。
  3. 协议回归优先于功能回归:大整数、加解密、JSON 体 413、登录态 ASYNC、Flyway locations------这些比「某个业务页面像素」更能决定能不能上联调。
  4. 库状态单独门禁:Flowable 引擎表、Flyway history、Redis 旧 Session(系列上文)各算一条;共享测试库被 8.x 写过就不要幻想「改个版本号回去」。
  5. 最后才合入主线 :Forge 是 6bf663717 合并兼容分支时才把主线校验与纯净版 SQL 规则一并保留;合并后立刻跑 Flyway 同号查重。

官方 Migration Guide 仍然要读,但它不会替你处理「生成器模板」「业务 Jackson 协议」「共享测试库被引擎主版本污染」这些工程细节------而这正是清单文存在的理由。

升级自查清单(建议收藏)

# 检查项 过关信号
1 preferred-json-mapper: jackson2 + 加解密仍在 Jackson2 Customizer 大整数 / 脱敏 / 金额回归与升前一致
2 MCP / 新 SDK 使用独立 Jackson3 @Qualifier mapper 业务 ObjectMapper 不被 Jackson3 顶掉
3 webmvc + Tomcat;JSON 体有读流限流(413) 超大 JSON 进不了加密 / 业务 Filter
4 ServiceImpl/IService 新包 + 生成器 .vm 同步 再生成 CRUD 仍可编译
5 Sa-Token Filter 覆盖 REQUEST / ASYNC / ERROR MCP / 异步重进仍有登录上下文
6 Flowable 主版本与库一致;禁止只改 schema.version 回退 7 / 8 不混用同一测试库
7 Flyway classpath:db/migration;合并后查同号双文件 启动无 checksum / duplicate version
8 (系列上文)自定义 Executor 时补 applicationTaskExecutor 或 mode=force 见 上一篇
9 (系列上文)Sa-Token 1.45 读旧 SaSessionForJacksonCustomized 同上:先查 Session,再查租户拦截器

写在最后

这篇是 Forge Admin Boot4 兼容系列第 2 篇 :偏「升级路径与可复用清单」;第 1 篇偏「双故障现场」。仓库地址以项目 README 为准。若你也在升 Boot 4,欢迎在评论区丢一条你卡最久的堆栈------下篇可以按读者出题继续拆(例如 Redisson 4 节点 API、Spring AI 2 与通义 milestone 的 ToolExecutionEligibilityPredicate 缺类等,我们 pitfalls 里也有实锤,本篇篇幅先停在五条主坑 + 清单)。

觉得能少踩一个坑的话,麻烦 点赞 + 收藏 这份表;收藏通常比点赞更救命。也欢迎把清单拷进你们团队的升级 RFC------改成自己的仓库路径即可,不必和 Forge 一一对应。

相关推荐
GetcharZp1 小时前
不止是企业知识库:腾讯开源 WeKnora,让文档变成可问答、可执行的知识系统
后端
Knight_AL1 小时前
别把 ThreadLocal 写进 Jackson Serializer
java·spring boot·spring
Song_RsHt1 小时前
Gateway (上):路由与转发,微服务的统一入口
java·笔记·后端·学习·gateway
paopaokaka_luck1 小时前
校园新闻推荐系统(DeepSeek新闻助手、个性化推荐算法、 Redis热词排行榜、ECharts运营分析、互动与实时通知、新闻运营闭环)
java·spring boot·mysql·spring·tomcat·echarts·intellij idea
yuniko-n1 小时前
【JUC】线程池
java·开发语言
小天源1 小时前
智叟云集政策监测技术方案——原文解析、证据提取与可核验摘要
java·服务器·数据库
凤山老林1 小时前
从零搭建企业 OAuth2 授权中心:Spring Boot 集成 Spring Authorization Server 与
数据库·spring boot·spring
yuzhiboyouye1 小时前
我现在得后端状况以及需要做的
java
小羊没烦恼!1 小时前
在.net中读写config文件的各种方法
java·大数据·运维·服务器·前端·数据库·oracle