升级不是Copy & Paste:Spring 4.3.0 升级到 5.3.39 实践

Dcr 21小时前 ⋅ 9 阅读

升级背景

1.技术债与代码规范化

  • 原有版本(4.3.0)发布于 2016 年,距今已有多年,依赖的 JDK、第三方库、构建插件等均较为陈旧。
  • 历史原因导致部分模块在路径管理、Bean 配置、事务管理等方面存在不规范实现,影响可维护性与可扩展性。
  • 升级可借机清理遗留代码、引入统一的编码规范,减少后续维护成本。

2.容器化与服务治理趋势

  • 近年来公司服务逐步向容器化和 Kubernetes 环境迁移,对服务的启动速度、健康检查、配置管理等有更高要求。
  • Spring 5.x 对响应式编程、WebFlux、Bean 初始化流程等有优化,能更好适配云原生部署环境。
  • 与 Spring Boot 2.x / 3.x 的生态配合更好,便于集成微服务治理组件(如 Spring Cloud Alibaba、Service Mesh)。同时也是为老项目转Spring Boot做铺垫

3.安全与依赖更新

  • Spring 4.3.0 已停止社区支持,存在未修复的安全漏洞。
  • 升级至 5.3.39 能获取官方安全补丁和长期支持(LTS)版本的保障。
  • 可同时升级依赖的 Jackson、Tomcat、Hibernate 等核心组件,提升安全性与性能。

4.为未来的 AI 智能体趋势做准备

  • 随着 AI 大模型和智能体技术在业务系统中的应用增多,后端框架需要具备更好的异步处理、事件驱动能力以及与 AI 服务的集成能力。
  • Spring 5.x 的响应式 API、WebFlux、函数式编程支持,为未来接入 AI Agent、实时流式处理(如 RAG、实时推理)提供了基础设施。
  • 通过升级可提前构建面向未来的可扩展架构,避免 AI 应用落地时因框架过旧而受限。

升级前准备

  • 项目依赖路径梳理 1.这种升级需要从最前端的工程开始,避免因依赖传递导致其他工程产生spring版本冲突控制项目风险; 2.项目内Dependency Analyzer 梳理引用的旧版本spring组件

升级过程中遇到的坑

1. 项目启动报错

org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping] for bean with name 'org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0'....nested exception is java.lang.ClassNotFoundException: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

原因: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 在 Spring 3.1 就已经标记为废弃(deprecated),到 Spring 5 就删除了。Spring 5 统一使用 RequestMappingHandlerMapping 来处理 @RequestMapping 注解的 Controller。

解决方法 删除RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 确保xml里有

<mvc:annotation-driven />

2. Spring 5.3.39 升级后 路径匹配规则 发生了变化

触发条件

例如接口声明 @RequestMapping(value = "/xxxx"), 前端发起的请求是 /xxxx.json ,旧版本可以访问,新版本却404

原因

旧版本(AntPathMatcher):路径匹配比较宽松 新版本(PathPatternParser):默认精确匹配,不会自动忽略 .json 这样的后缀。 如果方法上没有声明 .* 或显式的后缀匹配,Spring 会直接 404。

1.png

解决方法

方法1 (不推荐毕竟这属于以前欠下的技术债,最好还是规范请求路径)

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setUseSuffixPatternMatch(true);
    }
}

3.beforeCommit / beforeCompletion 执行时机的微调

触发条件

  • 在 TransactionSynchronization.beforeCommit(boolean readOnly) 或 beforeCompletion() 中做了依赖数据库写入结果的业务逻辑,例如提前更新缓存、调用外部接口、发 MQ 消息等

  • 升级到 Spring 5.3.39 后,这段逻辑在某些情况下 不会像之前一样被触发(特别是事务被标记 rollback-only 时)

原因分析

  • 在 5.3.39 前,Spring 即使事务标记为 rollback-only(但还没真正回滚)也会执行 beforeCommit

  • 在 5.3.39 后,Spring 严格遵循:

    ** 如果事务已经 rollback-only,则不会调用 beforeCommit。

    ** beforeCompletion 仍会执行,但在回滚场景里可能提前触发。

  • 这是为了避免在即将回滚的事务中提前做对外可见的状态变更(防止“幻读”式的业务错误)。

  • 如果确实要在提交前做准备,可以放到 beforeCompletion 并且判断事务状态

解决方法

  • 不要在 beforeCommit 中做依赖提交结果的逻辑(如发 MQ、写缓存),应该放到 afterCommit

4. afterCommit / afterCompletion 执行的更严格顺序

触发条件

  • 代码在 afterCompletion 里区分提交和回滚的逻辑,比如:
@Override
public void afterCompletion(int status) {
    if (status == STATUS_COMMITTED) {
        // 写缓存
    } else {
        // 清理资源
    }
}

  • 升级后发现,有些时候你预期的“提交”逻辑没被触发,或者执行时间点比以前晚。

原因分析

  • 5.3.39 后,Spring 将所有 afterCommit 放在真正的物理事务提交后执行(以前可能是在事务管理器完成提交阶段的早一点时间点就执行)。

  • afterCompletion 总会执行,但状态值来源更严格:

    ** STATUS_COMMITTED → 真正提交成功

    ** STATUS_ROLLED_BACK → 真正回滚完成

  • 对依赖事务状态判断的代码影响比较大,特别是链路中还有异步任务时。

解决方法

  • 如果是提交成功后的业务逻辑(如发消息、刷新缓存),全部迁移到 afterCommit,不要依赖 afterCompletion 判断提交状态。
  • 如果是清理资源,可以继续用 afterCompletion,但不要在这里做提交后才安全的操作。

升级带来的实际收益

1. 性能与内存优化

  • 启动速度可提升 10%-20%(取决于项目规模)
  • 内存占用减少,垃圾回收更稳定

2. 安全加固

  • 修复已知的数十个安全漏洞(包括反序列化、XSS 等)
  • 默认安全策略提升,减少人为配置失误

3. 生态兼容性

  • 无缝衔接 Spring Boot 2.x/3.x
  • 直接接入最新的 Spring Data、Spring Security、Spring Cloud 组件

4.未来维护成本降低

  • 从 4.3 到 5.3 是一次跨越式升级,后续迁移到 Spring 6 成本低很多
  • 避免继续堆积技术债务

全部评论: 0

    我有话说: