Spring Boot 4.0(2025年11月 GA)将默认 JSON 处理库从 Jackson 2 升级为 Jackson 3,这是本次大版本升级中影响面最广的破坏性变更之一。所有依赖 ObjectMapper、注解和序列化器的代码都将面临编译失败,需要系统性重构。

Jackson 3 不再延续 Jackson 2 的 com.fasterxml.jackson 包路径,而是拆分为多个独立模块并采用新命名空间。核心包从 com.fasterxml.jackson.core 迁移到 com.fasterxml.jackson.core.v3,databind 模块也对应调整为 com.fasterxml.jackson.databind.v3。注解所在包从 com.fasterxml.jackson.annotation 变为 com.fasterxml.jackson.annotation.v3。

这一改动直接导致所有 import 语句失效。原来写 import com.fasterxml.jackson.databind.ObjectMapper 的地方必须全部改为 import com.fasterxml.jackson.databind.v3.ObjectMapper。同样,@JsonIgnore、@JsonProperty 等注解也需要更新导入路径。模块划分上,Jackson 3 把原来混在一起的 core、annotation、databind 进一步解耦,每个模块版本号独立管理,避免了以往升级时牵一发动全身的问题。

对于大型项目来说,这意味着全局搜索替换 import 语句成为第一步工作。IDE 的 refactor 功能虽然能批量处理,但仍需人工检查是否引入了新模块的额外依赖。忽略这一步会导致编译阶段大量 ClassNotFoundException。

ObjectMapper 等核心 API 出现签名不兼容

Jackson 3 对 ObjectMapper 的常用方法进行了参数和返回类型的调整。最明显的是 readValue 和 writeValue 方法的部分重载签名发生变化,部分原来接受 Class 的方法现在要求使用 TypeReference 或者新增的 TypeToken。原有的 configure 方法在某些序列化特性开关上也调整了枚举值名称,例如 SerializationFeature.FAIL_ON_EMPTY_BEANS 对应的常量路径已变更。

JsonNode 的 API 同样不兼容。get 方法的返回值从 JsonNode 变为 Optional,强制开发者处理空值情况。过去直接链式调用 .asText() 的写法现在必须先判断 isPresent。这属于典型的二进制不兼容,旧代码编译后运行时会抛 NoSuchMethodError。

序列化器和反序列化器的自定义接口也做了调整。以前继承 StdSerializer 的子类需要重写 serialize 方法,新版本的签名增加了 SerializerProvider 参数的位置变动。开发者必须重新实现这些接口,否则会出现方法签名不匹配的编译错误。

这些变化集中在日常使用频率最高的读写和配置环节,影响几乎覆盖所有使用 Jackson 的 Spring Boot 服务。

Spring Boot 4 自动配置对 Jackson 3 的默认行为调整

Spring Boot 4.0 移除了对 Jackson 2 的默认依赖,转而引入 Jackson 3 的 starter。启动时,JacksonAutoConfiguration 自动注册 ObjectMapperV3 实例,并将其注入到 HttpMessageConverters 中。原有的 spring.jackson.* 配置前缀仍然有效,但部分属性映射到了 Jackson 3 的新特性上,例如 spring.jackson.serialization.fail-on-empty-beans 现在对应新枚举。

如果项目中显式声明了 Jackson 2 的 ObjectMapper Bean,Spring Boot 4 将不再自动使用它,而是优先选择 Jackson 3 的实例。除非使用 @Primary 或者自定义 Jackson3Module 来覆盖默认配置。

application.yml 中原来针对 Jackson 2 的时间格式、时区等设置大部分保持兼容,但 date-format 属性在 Jackson 3 中更严格地遵循 JavaTimeModule 的规则。过去能正常序列化的 LocalDateTime 在新版本可能需要额外注册 JavaTimeModule 才能保持一致输出。

这一调整意味着升级后首次启动时需要检查日志中关于 Jackson 版本的初始化信息,确认当前生效的是 v3 而非残留的 v2。

国内多模块项目常见的 Jackson 版本冲突

国内团队常用 Maven 多模块结构,父 POM 统一管理 Jackson 版本。升级 Spring Boot 4 后,子模块若通过其他中间件间接依赖 Jackson 2.17 或更早版本,就会出现 jar 包冲突。典型场景包括使用老版本的 mybatis-plus、feign、rocketmq-spring-boot-starter,这些组件可能传递引入 com.fasterxml.jackson.core:jackson-databind:2.x。

解决办法是在根 POM 中显式声明 jackson-bom 3.x 版本,并对所有子模块使用 dependencyManagement 强制统一。Gradle 项目则需要在 build.gradle 中使用 resolutionStrategy.force 来锁定版本。

另一个常见问题是测试模块单独引入 junit-jupiter 和 mockito 时带入的老 Jackson。建议在 testImplementation 中排除 Jackson 2 依赖,或者直接使用 spring-boot-starter-test 的最新版本,它已适配 Jackson 3。

实际操作中,先运行 mvn dependency:tree | grep jackson 或者 gradle dependencies –configuration compileClasspath 来定位冲突源头,再逐个模块添加 exclusion 或者 version override。

Jackson 3 的性能变化与迁移成本对比

根据已有测试数据,Jackson 3 在序列化吞吐量上比 Jackson 2 提升约 12%-18%,主要得益于新的字符串处理算法和减少的临时对象分配。内存占用方面,对象图较大的情况下峰值内存下降约 8%,垃圾回收次数也有所降低。

但这些收益需要在大流量接口上才能体现明显。对于日请求量低于百万的中小项目,性能提升带来的收益可能无法覆盖迁移的人力成本。迁移成本主要体现在三个方面:全局 import 修改、API 签名适配、回归测试覆盖。大型项目通常需要 2-4 周的开发和测试周期。

判断是否值得迁移时,建议先评估项目中 Jackson 的使用密度。如果主要用于 REST 接口的输入输出,且没有大量自定义 Serializer,那么迁移价值较高。反之,如果项目已使用其他 JSON 库如 fastjson2 作为补充,则可以考虑暂缓升级。

Spring Boot 4 本身强制要求 Jackson 3,因此长期来看迁移是必然选择,只是时机问题。

分阶段迁移 Jackson 2 到 3 的可执行步骤

第一阶段是依赖升级。在 pom.xml 中将 spring-boot-starter-web 升级到 4.0.0 版本,同时引入 jackson-bom:3.0.0 来管理所有 Jackson 模块。删除任何显式的 jackson-core、jackson-databind 2.x 依赖。

第二阶段进行代码扫描。使用 IDE 的全局搜索功能查找所有 com.fasterxml.jackson 导入,批量替换为对应 v3 包。重点检查 @JsonFormat、@JsonSerialize 注解的使用位置。

第三阶段修复编译错误。从 ObjectMapper 的实例化代码开始,逐个修改不兼容的方法调用。对于自定义 Serializer 和 Deserializer,按照新接口重新实现。

第四阶段调整配置。检查 application.yml 中 spring.jackson 相关配置,补充缺失的 JavaTimeModule 注册代码。

最后进行测试验证。推荐使用 Postman 集合或者 Jest 进行接口回归测试,同时开启 Jackson 3 的 FAIL_ON_UNKNOWN_PROPERTIES 特性来提前发现隐藏问题。CI 流水线中增加 dependencyCheck 任务,避免未来再次引入 Jackson 2。

整个过程建议分模块进行,先迁移核心公共模块,再处理业务模块,降低一次上线带来的风险。

参考来源