您所在位置:主页 > IT技术 >

JDK11升级JDK17最全实践干货来了

华宇网站建设 IT技术

01 前言在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!

京东技术公众号发布过文章JDK8升级JDK11的最全实践,相信读者阅读后已经对JDK11有了比较深入的了解。2021年9月14日,Oracle发布了可以长期支持的JDK17版本,那么从JDK11到JDK17,到底带来了哪些特性呢?亚毫秒级的ZGC效果到底怎么样呢?值得我们升级吗?而且升级过程会遇到哪些问题呢?带着这些问题,本篇文章将带来完整的JDK11升级JDK17最全实践。02     理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。1. 长期支持版本JDK17是Oracle官方在2021年9月14日发布的一个长期支持(LTS)版本,意味着它将获得长期的更新和支持,有助于保持程序的稳定性和可靠性。

2. 性能提升

更好的垃圾回收器。综合评估,从Java 8 升级到 Java 11,G1GC平均速度提升16.1%,ParallelGC为4.5%,从Java 11 升级到 Java 17,G1GC平均速度提升8.66%,ParallelGC为6.54%(基于OptaPlanner的用例基准测试表明)

最大的亮点是带来了稳定版的ZGC垃圾回收器,达到亚毫秒级停顿。

3. 新语法和特性

Switch表达式简化、Text Blocks文本块、instanceof 的模式匹配升级和NullPointerException提示信息改进等。

4. 支持最新的技术和框架

Spring framework6 和Spring Boot3 都默认使用 Java 17作为最低版本。

03   理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。

先给出结论:

1、JDK17相对于JDK8和JDK11,所有垃圾回收器的性能都有很明显的提升,特别是稳定版的ZGC垃圾回收器

2、不论任何机器配置下,都推荐使用ZGC,ZGC的停顿时间达到亚毫秒级,吞吐量也比较高

在JDOS平台上选择了不同配置的机器(2C4G、4C8G、8C16G),并分别使用JDK8、JDK11和JDK17进行部署和压测。

整个压测过程限时60分钟,用180个虚拟用户并发请求一个接口,每次接口请求都创建512Kb的数据。最终产出不同GC回收器的各项指标数据,来分析GC的性能提升效果。

以下是压测的性能情况:

04   OracleJDK和OpenJDK的选择  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目

2021年9月,Oracle宣布JDK17可以免费商用,直到下一个 LTS 版本之后继续提供整整一年,同时Oracle 将继续按照自 Java 9 以来的相同版本和时间表提供GPL下的Oracle OpenJDK 版本。

2023年9月,OracleJDK发布了新的LTS版本 JDK21,这就意味着从2024年9月开始,在生产环境使用 OracleJDK17 将需要付费。

OracleJDK和OpenJDK这两个之间没有真正的技术差别,因为针对Oracle JDK构建过程是基于OpenJDK的。自从JDK11开始,OracleJDK和OpenJDK在功能上基本相同,所以推荐使用 OpenJDK17 或其他开源的JDK版本,这些开源版本都是基于OpenJDK构建并提供长期支持的,比如:AdoptOpenJDK、RedHatOpenJDK。

https://blogs.oracle.com/java/post/oracle-jdk-releases-for-java-11-and-later

05   JDK11到JDK17带来了哪些新特性  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目

5.1  JVM改进    

1. ZGC垃圾回收器从实验性功能更改为正式产品功能,从JDK11引入以来,经过持续的迭代升级,目前已经足够稳定。需要手动开启,开启方式:-XX:+UseZGC

2. G1垃圾回收器仍然作为默认垃圾回收器,进行改进升级,主要包括可中止的混合收集集合、NUMA 可识别内存分配等

3. JDK14开始删除 CMS 垃圾回收器

4. JDK14开始弃用 ParallelScavenge 和 SerialOld GC 的组合使用

5. JDK15禁用偏向锁,默认禁用:-XX:+UseBiasedLocking

6. NullPointerException 提示信息改进

JDK14以前的出现NullPointerException时,只能定位到所在异常行,无法定位具体是哪个变量。改进后的NullPointerException,可以清晰描述具体变量,提升了空指针异常的可读性。

5.2  新语法特性    

switch表达式带来了简化式的编码方式,提供了新的分支切换方式,即 -> 符号,右则表达式方法体在执行完分支方法之后,自动结束 switch 分支,同时 -> 右则方法块中可以是表达式、代码块或者是手动抛出的异常。

传统写法

新写法

5.2.2 Text Blocks文本块(5星推荐)

通过编写 """,来减少转义字符和换行符,达到简化代码和提高代码可读性的目的。

record 是 JDK 14 引入的关键字,用于声明不可变的数据类。它适用于存储纯粹的值类型数据,如接口传输数据、坐标点和只读的日志记录。与 lombok 相比,record 简化了定义纯粹数据类型的过程。由于 record 类是不可变的,成员变量只能设置一次且无法更改,无需提供显式的 setter() 方法。

1. 定义Point类,使用关键字record,未定义get/set

2. 查看编译后的字节码文件

3. 使用Point类

5.2.4 instanceof 的模式匹配升级

instanceof类型判断再也不需要强制转换

5.2.5 密封的类和接口

JDK15开始,引入了sealed普通类或接口类,这些类只允许被指定的类或者interface进行扩展和实现。

使用修饰符sealed,您可以将一个类声明为密封类。密封的类使用关键字permits列出可以直接扩展它的类。子类可以是最终的,非密封的或密封的。

比较实用的一个特性,可以用来限制类的层次结构

5.2.6 其他优化和升级

感兴趣的读者,推荐阅读OpenJDK官方文档说明,从JDK11到JDK17的改动:

06   升级步骤  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目

6.1  JDK选择    

OpenJDK17下载:

行云镜像:

jdt-base-tomcat/java-jdt-centos7.4-openjdk-17.0.2-tomcat8.0.53

6.2 pom编译配置升级    

maven编译所需JDK升级至17

6.3 SpringBoot升级    

SpringBoot版本升级到2.7.15,Spring版本升级为5.3.29

为什么不升级到SpringBoot3?

Spring Boot 3.0最低要求 Java 17,SpringBoot3.0带来了很多变化,和SpringBoot2差异较大。 考虑到公司很多中间件都是基于SpringBoot2构建的,所以此处推荐升级到SpringBoot2的最高版本2.7.15。

POM升级

也可以通过设置dependencyManagement的方式:

循环依赖问题

SpringBoot升级到2.7.15后,如果应用中存在循环依赖的问题,启动时会报如下错误:

原因:官方文档不鼓励循环依赖引用,默认情况下是禁止的

解决方案:

第一种:推荐更新应用中bean的依赖关系来解决

第二种:配置文件中加入以下配置,为了和旧版本保持一致,此配置推荐添加

6.4 常用中间件升级    

如果不升级,编译时会报错如下:

异常:

解决方案:

properties配置:

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

参考:https://developer.aliyun.com/article/950787

异常:

原因:

Java11 华宇网址 删除了 Java EE modules,其中就包括 java.xml.bind (JAXB)。

解决方案:

手动引入如下包即可

使用 Concrete时,启动时异常:

原因:

分析下Concrete报错的原因,如下图,包内com.wangyin.concrete.spring.ConcreteConfigProcessor#postProcessAfterInitialization(212行)的实现逻辑

解决方案:

1. 在JVM启动参数中设置--add-opens jdk.proxy2来开启私有字段的访问,但因为动态代理生成的包名是随机不明确的,所以这种方案不可行。JDK官方文档也明确表示不支持访问动态代理内部的随机字段。

2. 代码修改,只需把 f.setAccessible(true) 移到 Modifier.isStatic(f.getModifiers()) 的判断下方即可。原因是方法 Modifier.isStatic(f.getModifiers()) 本来就要跳过静态字段,这样修改直接避免了访问。推动concrete团队修复问题。

6.5 JVM启动参数配置   

启动参数中配置:-XX:+UseZGC

华宇网址

升级JDK17后,项目启动时可能会遇到如下两种类型的异常:

异常原因:

自从JDK9中引入了模块化功能后,再到JDK17,对于包扫描和反射的权限控制更加的严格。常见的库比如(Spring)大量用到包扫描和反射,所以常出现此错误。

解决方案:

一个粗暴的解决办法是将没开放的module强制对外开放,即保持和Java9之前的版本一致。

?--add-exports导出包,意味着其中的所有公共类型和成员都可以在编译和运行时访问。

?--add-opens打开包,意味着其中的所有类型和成员(不仅是公共类型)都可以在运行时访问。

主要区别在于允许“深度反射”,即非公共成员的访问,才可以调用

SGM需要加入:

R2M需要加入:

Ducc需要加入:

AKS需要加入:

6.6 启动后的验证   

1. 推荐先升级JDK11,再到JDK17,一边升级一边进行验证观察

2. 观察日志是否有异常,特别是上面说到的启动时异常

3. 观察监控类软件,比如SGM、UMP等监控是否正常

4. 推荐逐步有序切量,并做好常态化压测,防止影响核心业务

5. 升级完成后,最好能做个全流程的功能测试,防止功能异常

07   总结  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结华宇网址构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目升级后,除了可以使用新的语法特性,最大的亮点是可以使用亚毫秒级停顿的GC性能(至少百倍的GC性能提升),所以 强烈建议升级到JDK17。整个升级过程并不复杂,主要涉及到中间件版本的升级和启动参数的配置。

如果还停留在JDK8,推荐先升级JDK11,再到JDK17,具体升级步骤先参考上篇文章“JDK8升级JDK11最全实践干货来了”,再参考本章中的升级步骤。

希望以上分享可以给大家带来实际的帮助,升级过程中如果遇到问题,欢迎大家在评论区回复。

上一篇:华宇注册京东二面:为什么需要分布式ID?你项目中是怎么做的?

下一篇:华宇网址无服务器并不意味着DevOpsLess或NoOps
相关文章
评论留言