springboot项目从Java8升级到jdk17的全过程记录

1,490 阅读4分钟

项目用到哪些组件

项目是使用spring cloud生态下的微服务, 之前用的注册中心是eureka, 后来切换到nacos, 熔断降级用的是hystrix, 基本上都是spring cloud相关的服务组件, 除了es、mq之外,大部分都是用的starter包. 相关组件如下:

  • springboot
  • springcloud
  • 注册中心nacos
  • 配置中心nacos
  • rocketMQ
  • elasticsearch
  • redis
  • mysql
  • pagehelper
  • tkmybatis
  • orika对象copy
  • lombok
  • prometheus业务监控
  • liteflow 流程编排
  • swagger

升级目标

  • jdk --> 17
  • spring-boot目标版本 3.1.0
  • spring-cloud-dependencies目标版本 2022.0.2
  • *spring-cloud-alibaba-dependencies目标版本 2022.0.0.0-RC2 上述主要的框架版本基本是当时最新的发行版, 其他工具类、依赖包等也会升级到最新版本, 有一些组件已经废弃,比如hystrix, 需要用sentinel替换. 下面是整个升级的步骤

为什么升级到jdk17

因为一些高版本的组件只支持jdk17. 作为技术人, 想用最新的技术总是没有错的. jdk17以及相关的组件升级提供很多新的特性,尤其是GC提升很大,上线后服务内存占用降低一半左右,等于间接节约了服务器成本,代码运行效率也有一些提升,这可是实打实的降本增效, 至于升级后是否还有其他好处,可以自行搜索.

升级改造步骤

准备jdk17的环境

建议使用官方的JDK版本, 当然也可以使用[Amazon Corretto 17](Downloads for Amazon Corretto 17 - Amazon Corretto 17) 由于本地会同时存在两个版本的jdk,可以自行搜索本地管理两个jdk版本的方法

升级组件jar包依赖

大部分组件包都可以使用最新版,如果不升级,可能会有问题. maven可以用mvn versions:display-dependency-updates命令检查依赖项更新, 检查结束会输出以下信息(仅截取部分):

[INFO] The following dependencies in Dependencies have newer versions:
[INFO]   com.alibaba:easyexcel ................................. 3.3.1 -> 3.3.2
[INFO]   com.alibaba:fastjson ................................ 1.2.83 -> 2.0.36
[INFO]   com.aliyun.openservices:ons-client ...... 1.8.8.8.Final -> 2.0.5.Final
[INFO]   com.aliyun.oss:aliyun-sdk-oss ....................... 3.16.3 -> 3.17.0
[INFO]   com.github.pagehelper:pagehelper-spring-boot-starter ...
[INFO]                                                           1.4.6 -> 1.4.7
[INFO]   com.mysql:mysql-connector-j .......................... 8.0.33 -> 8.1.0

当然,不是所有组件都可以升级, 比如fastjson2.x 对1.x的版本不兼容, ons-client也会有兼容问题, 此类组件可以不升级.

项目中引入的公司的二方包可能也需要提前升级, 比如我们有个jar包专门用来上报业务数据, 也需要升级兼容jdk17

SpringBoot 2.0升级到3.0 (需要修改pom.xml和代码)

swagger 2.0升级到3.0 (需要修改pom.xml和代码)

先替换为springdoc, 再升级到springdoc v2版本, swagger api变动较多

javaEE迁移到jakartaEE (需要修改pom.xml和代码)

javaEE已经被更名为Jakarta EE, 需要将javax开头的包修改为jakarta

注意: 如果你的项目用到了tk.mapper则实体类依赖的javax.persistence不可迁移到jakarta.persistence(因为tk.mpper官方不再维护, 不支持jakarta.persistence)

sleuth迁移到micrometer-metrics (需要修改pom.xml和代码, 没有强需求的项目可以先直接移除sleuth)

hystrix迁移到sentinel (需要修改pom.xml和代码)

saturn迁移到xxl-job (需要修改pom.xml和代码)

saturn官方已经3年不再维护, 无法支持jdk17和springbot3.0, 且对应用启动性能有影响, 考虑迁移到xxl-job

升级后遇到的问题

spring.main.allow-circular-references=true
  • 双斜杠url无法访问
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
  • springboot2.4以后版本, 单元测试无法注入CollectorRegistry, 解决方法:增加@AutoConfigureObservability注解
  • javax-validation兼容性问题, 建议引入spring-boot-starter-validation解决
  • redis报错问题:yml配置改成spring.redis 改成 spring.data.redis
  • Orika对象copy, 运行时报错, 可以用mapstruct替换, 或者直接用get/set
  • 入参String转Date报错,原因: springboot3.x关于日期格式的配置有改动,导致原数据格式化配置失效, 增加如下配置:
spring.mvc.format.date=yyyy-MM-dd HH:mm:ss
  • 当spring.cloud.loadbalancer.cache.enabled为true时,被调用方重启会导致调用方找不到服务ip出现以下报错:java.net.NoRouteToHostException, 此问题属于spring-cloud-loadbalancer在开启了caffeine导致的bug, 具体issues 在调用方重启后没有将缓存更新导致后续调用全部走到旧的ip. 该问题出现条件比较苛刻, 我们用的是nacos注册中心, 直接把开启nacos loadbalance, 不用默认的loadbalance, 或者把loadbalancer缓存关闭也可以
#spring-cloud-loadbalance使用caffeine cache有bug,会导致缓存不更新,这里不要开启缓存
#或直接使用nacos的loadbalance实现
spring.cloud.loadbalancer.cache.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true