JDK21升级初体验
受万众瞩目的jdk21已经发布一段时间了,这个版本新增了哪些新特性网上已经有了很多文章,我这边也不再多述。 刚好我这这边负责的有个新服务,目前的服务请求量也不大,比较适合新技术尝鲜,于是便拿过来做了下升级。
为什么升级
升级一个服务总得需要个理由(需要吗?),特别是升级JDK这种基础运行环境的, 总不能和技术总监、运维说“因为闲着没事干,所以想要给自己找些事情做,于是来升级一下JDK”吧(这是说谁呢)。 升级这个不仅有时间成本,还有风险成本,收益总是要大于成本才行。由于我这边这个服务9月份刚创建,创建的时候使用的就是JDK17,17至21没有破坏性更新,而且是我自己独立维护的,所以风险成本可控,而且最近确实是比较闲,所以时间也有, 收益则是我比较期待的虚拟线程和分代ZGC。
版本选择
JKD版本
首先是JDK版本,是Oracle JDK还是OpenJDK,理论上两者在运行时不会有啥区别,由于Oracle JDK以后可能涉及商业收费问题,我们这里就选择了OpenJDK。
spring版本
然后是spring版本,之前使用的spring-boot版本为2.7.15,spring-cloud版本为2021.0.8,注册中心和配置中心用了nacos,所以还有spring-alibaba-cloud版本为2021.0.5.0。
spring-boot的最新版本3.2.0对虚拟线程做了支持,所以本想升级至此版本的,但spring-boot 3.2.0所对应的spring-cloud版本是2023.0.0-RC1,
当时还未发布正式版本[1],而且spring-alibaba-cloud也尚未对spring-boot 3.2.0以及spring-cloud2023.0.0做支持。
最终spring-boot版本升级至3.1.6, spring-cloud升级至2022.0.4,spring-alibaba-cloud升级至2022.0.0.00
开始升级
服务原JDK就是17,JDK17至JDK21没有破坏性的更新,所以升级是比较简单的。spring版本按照上述进行升级。然后由于spring-boot 2.7.15为了兼容JDK1.8,
所以仍然使用了javax.annotation包下的大量注解,升级至3.x后全部更换为jakarta.annotation包下注解,所以我们也需要将开发时写的注解进行跟换,
修改时直接全局替换javax为jakarta,由于并不是所有的javax全部迁移至jakarta,所以编译一下看下报错,就可以找到仍在javax下的类,然后还原一下即可。
然后是一些包的兼容性问题,由于spring boot 3.x系别发布很久了,所以基本上在更新的包都做了兼容,除了个别地包比如rocketmq-spring(rocketMQ捐献给apache后就变成后娘养的了,似乎没啥人维护了)。
rocketmq-spring-boot-starter依赖会在启动的时候报找不到RocketMQTemplate错误,办法是在application上添加注解@import(RocketMQAutoConfiguration.class)
或者新建文件src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports,里面添加如下内容
1 | |
启动测试
编译打包,发布测试,由于没破坏新更新,所以基本没啥问题,服务在测试环境也跑了10多天了,也没啥问题。
新特性使用
分代ZGC
启动分代ZGC需要添加如下启动参数
1 | |
由于服务流量不大,所以没法看出什么问题,这个得后续观察
虚拟线程
虚拟线程池的使用很简单,下面是简单的示例
1 | |
然后虚拟线程的创建方式,线程创建后会直接启动
1 | |
或者创建后手动启动
1 | |
虚拟线程对比普通线程,优点主要是更低的资源开销,由于虚拟线程不和操作系统线程一一绑定,所以可以创建更多的虚拟线程,不用担心系统资源耗尽 除此之外,虚拟线程就和普通线程一样,都比较适合IO密集型操作,而对CPU密集型的计算,提高线程数量都没有效益。
结束
以上便是此次升级的过程。总体上来说,如果项目本身的JDK版本较高,升级起来是比较顺利的,如果项目使用的是JDK1.8,那么还是自求多福吧。
现在技术一直在发展,新的项目还是比较推荐使用新的技术,即使不直接使用JDK21,17也是值得使用的,以后升级21也方便。如果一直有着“版本随便出,换8算我输”的心态,那么离成为“老顽固”也不远了。
- 至本文发布时,spring-cloud最新版已经release,版本号为2023.0.0 ↩