从JDK8升级到JDK17
扫描二维码随身看资讯
使用手机 二维码应用 扫描右侧二维码,您可以
1. 在手机上细细品读~
2. 分享给您的微信好友或朋友圈~
一、概述
鉴于 JDK8 已经是老古董,还有性能问题,兼且各个公司已经不再维护 1.8 的 JDK ,所以升级 公司的核心产品之一 的后端到 JDK 到 17 是相对要紧的事情。
通过升级到 jdk17 ,具有以下好处:
- 不要在头疼同时适应两个 jdk , 放下适应 JDK8 的负担
- 在生产环境基本上只需要部署一个 jdk 即可
- 具有更好的性能
- 能够利用上更好更新的组件版本。例如 springboot3,spring6.x都是基于jdk17的。
- 更好的安全性。这对于项目很重要。因为许多客户会安排安全测试,过时的jdk是一个不好解决的问题。升级到jdk17能够更好解决这个问题
- 更好的竞争能力。当我们的核心jdk是17的时候,毫无疑问比那些还沉滞在jdk8的竞争对手更好,尤其是功能相差不大的情况下。
本次升级后端,大概耗费了一周的时间,其次 httpsecurity 耗费了比较多的时间。
整体上,还算顺利。
二、步骤详情
总体上遵循以下步骤:
(1) 升级准备
(2) 确定 spring 组件版本
到 spring.io 上看了下,选择 springboot-3.3.0
(3) 确定其它组件版本
(4) 升级有关代码
(5) 调整其它配置
(6) 解决有关异常
(7) 测试
(8) 完成升级
2.1. 升级准备
由于 这 是一个大的版本升级,所以需要做以下准备:
(1) 确认是否能升级
除了前文提到的原因,还需要确定当前这个产品是否可以升级,毕竟 JDK17 和 JDK1.8 不一样,且升级了 JDK17 后,有关的组件都要一起升级(是否有相关的版本,相关版本是否稳定 ?)
考虑到 我们的产品 没有使用太多的三方软件,即使有,也都是流行的
现在 jdk17 都已经发布了快 3 年了;有很多其它公司也升级到了 jdk17;部分公司已经把他们的产品升级到JDK21了。
结合这些因素, 产品升级 到 jdk17 不存在技术障碍!
之所以没有考虑立刻升级到JDK21,是因为其它很多产品都在JDK17,其次一次性到21,没有那么大把握。步子太大,会不会扯蛋了?
虽然官方的文档说springboot3.3.x支持JDK22。但是由于三方组件的存在,导致不敢一次性迈出太大的步子。
(2) 在 git/svn 上开一个分支,或者直接开一个新的仓库 , 不要影响现有的主干代码
2.2. spring 组件版本
在 spring.io 上可以看到可用的版本,本着使用最新可用版本的原则,选择了 :
- springboot-3.3.1 (ga)
- spring-6.1.10 这是 springboot 限定的版本,所以只需要选择 springboot 版本即可
按照 spring惯例 ,当升级的时候,通常相关的组件都是一期升级的,所以总的来说,只要指定 springboot 版本即可。
2.3. 确定其它组件版本
分类 |
组件 |
功能描述 |
旧版本 |
升级 |
新版本 |
说明 |
数据存取 |
druid-spring-boot-starter |
数据连接和连接池管理 |
1.2.11 |
是 |
1.2.23 |
核心组件,必须升级 |
jdbc驱动 |
* |
jdbc连接 |
|
否 |
|
主要看各个厂家,考虑到 jdbc驱动都是比较成熟的,在jdk17中运行,问题应该也不大 |
消息队列 |
org.apache.rocketmq/rocketmq-client |
amqp |
5.1.0 |
否 |
|
暂时不升级,这个需要较长时间的测试 |
http请求 |
httpclient,httpcore |
rest请求 |
4.5.13 |
是 |
5.3.1/5.2.4 |
原来是: org.apache.httpcomPONEnts/httpclient 现在是: org.apache.httpcomponents.client5/httpclient5 |
http |
javax.servlet/javax.servlet-api |
servlet |
4.0.1 |
否 |
|
移除 |
http |
jakarta.servlet/jakarta.servlet-api |
servlet |
6.0.0 |
否 |
|
新增。用于替代 javax.servlet-api |
JSON |
fastjson2 |
JSON |
2.0.32 |
是 |
2.0.51 |
fastjson2bug较多,尽可能升级下 |
JSON |
com.jayway.jsonpath/json-path |
JSON路径分析 |
2.8.0 |
否 |
|
|
ORM |
mybatis-spring-boot-starter |
orm |
2.2.2 |
是 |
3.0.3 |
不升级会导致 mybatis有关bean初始化异常 |
ORM |
pagehelper-spring-boot-starter |
分页 |
1.4.3 |
是 |
2.1.0 |
被 mybatis依赖 |
ORM |
jsqlparser |
sql解析 |
4.2 |
是 |
4.7 |
被 pageHelper依赖 |
XML |
javax.xml.bind/jaxb-api |
XML 解析 |
2.3.1 |
否 |
|
暂时不可替代,不可删除,也不需要升级 |
文档 |
swagger |
文档 |
|
否 |
|
从现有版本移除 |
定时 /调度 |
quartz |
定时 /调度 |
2.3.2 |
否 |
|
|
通用工具 |
org.apache.commons/common-lang3 |
|
3.12.0 |
是 |
3.14.0 |
|
通用工具 |
org.apache.commons/commons-pool2 |
|
2.9.0 |
是 |
2.12.0 |
|
通用工具 |
commons-io/commons-io |
|
2.11.0 |
否 |
|
|
通用工具 |
commons-fileupload/commons-fileupload |
|
1.4 |
否 |
|
|
存储 |
minio |
|
8.2.1 |
否 |
|
|
编译 |
maven-compiler-plugin |
编译 |
3.1 |
是 |
3.13.0 |
|
注:
- 主要考虑到核心组件即可,其它的小组件遇到了再解决。
- 有什么版本可用,可以访问 https://mvnrepository.com ,或则各个组件官网(一般是 GitHub), 或者是国内镜像网站,例如阿里的 https://developer.aliyun.com/mvn/search
- 部分组件版本必须在升级中调试后才可以确定
2.4. 升级有关代码
当更换了以下组件之后,需要尽快修改代码,修改的原因主要包含:
(1) 配置变更
主要是 spring 升级导致,可能需要修改配置。当然也可能是其它的组件
(2) 包路径变更
(3) 方法不存在
(4) 方法过时
这个需要特别注意 - 如果可能应该尽量把过时的方法移除掉,替换为正常的方法。
2.4.1. 修改 yml 配置
- 修改范围 -spring.redis 修改为 spring.data.redis-- 这是 spring 要扩大 spring.data 的范围
在spring.data的域名之下,有很多的内容,远不止redis.除了基本的JDBC,还有Rest,elasticsearch,jpd,ldap等等。
- 添加参数( bean 相关 )
spring: main: allow-circular-references: true allow-bean-definition-overriding: true |
在 spring6.1.10 中,这两个属性默认是 false. 如果你的项目不存在循环引用,或者覆盖定义的情况,那么可以不添加 .
- 移除配置
移除 swagger 配置 - 这个太垃圾,过分入侵,还浪费了自有的注释,增大程序员的工作量
希望有直接能够利用javaDoc的类似组件。
2.4.2. java 基础类型有关的
基础类型主要指 Integer,Long,BigDecimal,BigInteger 等等。
在 jdk17 中,许多方法已经被标注为过时 (deprecated) 。
(1) java 基类 new Class("xxx") 需要修改为 Class.valueOf("xxx")
new Long("xx"),new Integer("xxx"),new Byte("xx"),new Short("")
这些都要修改为对应的 valueOf("xxx") 。
jdk 这么做,主要是出于性能考虑,尤其针对 Integer 。
(2) Class.newInstance()
需要把这个替换为 getDeclaredConstructor().newInstance()
(3) Spring.Base64Util 过时,改用 apache 的 Base64
(4) ruoyi 自身的 Base64, 移除掉,避免和 apache 的冲突。
(5) ruoyi 自身的 md5Util 移除
从 spring 自身的改变来看, spring 也逐渐向 java 标准和阿帕奇基金会靠近,一个是为了标准,其次是避免浪费
时间,最后是不要给 spring 用户带来困扰。 spring 只要做好自己的就行了。
ruoyi如果用于项目还是可以的,但是用于产品开发还是需要进行较多的改造。 因为产品要求更高的安全、适应度、性能等。
2.4.3. servlet 相关
由于在 jdk17 中移除了 javax 的部分包,所以 很多 javax.xxx 都需要修改 jakarta.xxx
这里主要包含:
(1) javax.servlet
(2) javax.annotation
其它 javax.net,javax.sql 等则继续保留着。
2.4.4. httpclient 相关
具体略,总之需要修改。
httpclient5 有重大变更:支持 http2, 异步支持,更好的连接池等
2.4.5. spring-security
这个改变比较大,在 spring6.x 主要通过注解和定义 bean 来实现 spring-security 配置,而在 5.x 中,则是通过扩展 WebSecurityConfigurerAdapter 来实现。
@Configuration @EnableWebSecurity @EnableGlobalAuthentication @EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) public class SecurityConfig { }
|
注意,不要去 override 已有的实现,否则配置还是比较麻烦的。
spring 的思路就是你可以改配置,改零件,但是不要改核心。如果要改核心,那么太费劲了。
在这个类中实现以下几个 bean 即可:
- AuthenticationProvider
- AuthenticationManager
- SecurityFilterChain
- BCryptPasswordEncoder
其中 SecurityFilterChain 是关键,这里主要配置白名单 。
另外一个变化是,禁用了默认的 logout, 而是新增了一个 /logout 接口:
/** * 执行退出 * @param request * @return * @since 1.5 */ @PostMapping("/logout") public AjaxResult logout(HttpServletRequest request) { try { LoginUser user=SecurityUtils. getLoginUser (); String key=CacheConstants. LOGIN_TOKEN_KEY + user.getToken(); redisCache.deleteObject(key); return AjaxResult. success (); } catch (Exception e) { //如果有异常,则证明已经退出了,不要阻拦 return AjaxResult. success (); } } |
2.4.6. jsqlparser
主要是因为 pageHelper 升级了。
当然产品 本身也有用到 jsqlparser 。
2.5. 调整其它配置
主要是编译方面的配置。
由于升级了 jdk ,包括核心组件 maven-compiler-plugin , 所以有些原来的默认设置需要进行调整。
2.5.1. 调整编译选项
在 eclipse 中,其实只需要设置 pom.xml 中配置即可,无需修改工程的环境配置。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.13.0</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> < parameters >true</ parameters > </configuration> </plugin> |
红色部分添加上去,并设置为 true 。
如果不添加这个,那么 spirng 中很多需要通过反射获取信息的方法可能存在问题。
因为这个选项会让 java 把 .java 编译为 .class 的时候,保留方法的名称,而不是把方法名称随意修改为不认识的名称。
2.6. 解决有关异常
2.6.1. bean 异常
2.6.1.1. 循环引用和覆盖
如前,主要新版本中,有些参数修改了默认值,所以修改如下:
spring: main: allow-circular-references: true allow-bean-definition-overriding: true |
2.6.1.2. @Primary 问题
当有多个 Datasource 类型的 Bean ,或者类似其它的,则必须为 Bean 添加 @Primary 的注解,否则回报告异常。
Parameter 0 of method sqlSessionFactory in com.ruoyi.framework.config.db.MyBatisConfig required a single bean, but 3 were found:
触发异常的具体代码如下:
而在以前的版本中不存在这个!
解决方式有两个:
(1) 在参数上简单添加 @Qualifier("masterDataSource") -- 解决了 mybatis, 但是还要解决 quartz 等等。放弃这个方法
(2) 直接修改定义 DataSource 的地方,为主 bean 添加 @Primary ,就用这个✔
2.6.2. jackson 序列化异常
无法处理 key 类型不是 String 类型 , 例如如果是以下类型的 JSON
{ "batchDetail": { 1: "good" } } |
在序列化的时候会报告异常:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
必须自定义 HttpMessgeConverter ,以便可以自定义处理这种类型的 key 。
但这会导致自定义白名单功能错误,所以还需要调整白名单功能
2.6.3. factoryBeanObjectType 异常
经过定位,这是 mybatis 没有升级导致的。
注:一开始的时候,并没有立刻要升级 mybatis ,虽然意识到了,但是并没有那么做。
2.7. 测试
(1) 每个地方都需要测试
(2) 反复测试
这是总的原则。
测试需要持续较长时间,严格而言,需要再考费一个月左右。
从目前来看,总体是可用!
从性能上看,JDK17的程序的确响应更快一些,从页面的响应也可以看出来!
2.8. 完成升级
完成升级后,关闭原来 git 上代码的权限,设置为只读,并通知有关人。
索尼克力量速度之战 手机版最新版
篮下王者内置菜单版下载 v1.1.2 安卓版
暗区突围正式版
真实拳击2无限金币钻石版下载 v1.47.4 安卓版
狂点妖妖灵官方版 v1.0.7.8 安卓版
云中奇谭0.1折 v1.0.2 安卓版
暗黑破坏神不朽华为版下载 v3.0.1 安卓版
塔尔战纪无限钻石版下载 v1.0.1 安卓版
最强蜗牛破解版无限内购单机版 v0.12.240614.02-0.3.755 安卓版
王者荣耀国际服 官网链接入口
托卡美发沙龙4可化妆免费 v2.5 安卓版
townscaper 免费下载
MONOPOLY GO安卓汉化版下载 v1.24.0 最新版
丹达拉:恐惧试炼 手机版
- 1
加查之花 正版
- 2
爪女孩 最新版
- 3
企鹅岛 官方正版中文版
- 4
捕鱼大世界 无限金币版
- 5
球球英雄 手游
- 6
情商天花板 2024最新版
- 7
内蒙打大a真人版
- 8
烦人的村民 手机版
- 9
跳跃之王手游
- 10
蛋仔派对 国服版本