当前位置: 首页 > news >正文

企业级JDK升级思路分享(一)JDK11升级到JDK17

文章目录

  • 前言
  • 应该使用哪个供应商的JDK?
  • JDK17到底快了多少?
    • 有关GC的几篇文章
  • 升级思路
    • 阅读官方升级指南
    • 升级到JDK17后一些代码不兼容的问题
    • 升级到JDK17后如何确保代码中的反射可以正常调用?
      • 找出哪些第三方库无法执行反射
    • 将运行时JDK改为JDK17
      • 优化Build Java应用时的Jenkins Job
    • 将编译时JDK改为JDK17
    • 通知开发切换为JDK17
  • 写在最后

前言

我司Java应用有10多个,凡是涉及到基础架构及其配置的升级,例如:操作系统,Apache,Tomcat,pom.xml中的第三方依赖,以及JDK等。都要进行全平台统一升级和维护。所以一些看似简单的工作,由于涉及的Java应用之多,代码之复杂,反而需要我们更加细心、谨慎。

我司于去年将JDK从JDK8升级到JDK11,今年计划将JDK从JDK11升级到JDK17。升级到JDK17的任务由我负责,以下为升级过程中的一些思考和做法。该思路不局限于JDK11升级到JDK17,之后的JDK升级也同样适用。

如果你们公司现在也面临将JDK8升级到JDK11或JDK17的情况,推荐阅读京东技术团队关于升级JDK的文章。总的来说,我们升级过程中遇到的问题和他们遇到的非常像,相似度在80%。可能看完他们的文章,都不需要读我的文章了。

  1. JDK8升级到JDK11
  2. JDK11升级到JDK17

应该使用哪个供应商的JDK?

之所以有这个问题是因为Java被Oracle收购之后,Oracle JDK 8u202版本之后的JDK开始收费。如果你们公司现在用的还是Oracle JDK 8u202之前的版本,那么在升级时势必要面临抉择。

目前市面上JDK的供应商很多,有Oracle,RedHat,还有开源的Adoptium Eclipse Temurin。这些JDK之前到底有什么不同?建议阅读一个韩国工程师写的 Which Version of JDK Should I Use?,有助于各位了解目前JDK的供应商和各个版本的JDK的不同。

由于我们不考虑商用,以开源的优先,所以我们选择Adoptium Eclipse Temurin,并根据其Release Roadmap以及实际情况来选择进行后续的升级。

JDK17到底快了多少?

上面京东技术团队的文章中有简要描述,这里再出几个文章链接

  1. How much faster is Java 17?
  2. GC progress from JDK 8 to JDK 17
  3. 一个快速比较各版本JVM之间不同的网页小工具

有关GC的几篇文章

  1. Bending pause times to your will with Generational ZGC
  2. netflix关于Java的文章
  3. 有关ZGC的表现的文章

升级思路

阅读官方升级指南

仔细阅读Oracle官方的升级到JDK17的迁移指南。虽然我们使用的是开源的JDK而不是付费的Oralce JDK,但对于一些JDK标准的变动,二者是保持一致的。

升级到JDK17后一些代码不兼容的问题

我们碰到了一个关于空指针异常消息判断的不兼容

在JDK11中

public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        if (s == null) {
            throw new NumberFormatException("null");
        }	
}

在JDK17中

public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        if (s == null) {
            throw new NumberFormatException("Cannot parse null string");
        }
}

有些开发人员,在处理异常时根据异常的字符串进行了判断,此时升级到JDK17,此判断无效,导致代码出现bug。

Fix: 修改判断空指针的逻辑,不允许根据异常消息的字符串进行判断

升级到JDK17后如何确保代码中的反射可以正常调用?

在阅读Oracle JDK17升级指南时,我发现了一段描述在这里插入图片描述
对于还在使用JDK8的同学来说,要理解这段话,需要了解一个小背景。在JDK9开始,JDK推出了Module System的概念,即对JDK 的包进行了更细致的切分,并对代码反射的访问权限进一步严格限制。

不了解Module System的可以看一下京东技术团队 JDK8升级到JDK11有关模块化的说明或自行Google相关知识。

JDK9-15虽然已经采用模块化,但是对于一些代码反射的访问权限并没有限制很严格,用户依然可以通过添加 --illegal-access=permit 来使得反射可以顺利进行。

从JDK16开始默认禁止所有非法反射访问 --illegal-access=deny(即如果想要通过反射访问某个包,该包在模块文件module-info中必须使用opens指令声明)。但是JDK16中还是可以修改为permit

从JDK17开始–illegal-access将不再有效(见JEP 403),JVM启动时会忽略该选项。

找出哪些第三方库无法执行反射

了解了上述背景知识之后,再来看实际遇到的问题。这么多Java应用都在使用JDK11,代码之多,使用的第三方依赖之多,如何找出来哪些代码的反射是在JDK17中不被允许的呢?

  1. 为JVM添加启动参数--illegal-access=warn 并将该参数应用到所有Java应用的测试以及产品环境中,测试环境每天有大量的auto smoke test帮我们做测试。 定期分析测试环境和产品环境日志,看日志中是否有类似日志
    WARNING: Illegal reflective access by
    
  2. 步骤1 应用到产品环境一段时间后,如果有上述警告日志,则根据实际情况添加–add-opens参数,例如
    --add-opens=java.desktop/javax.swing=ALL-UNNAMED
    
    也可以不加=号,JDK官方关于此写法的讨论
    --add-opens java.desktop/javax.swing=ALL-UNNAMED
    
    但通常建议加上=号
    然后继续分析日志,看是否还有步骤1的警告日志
  3. 经过上述2个步骤一段时间的验证,将测试环境和产品环境JVM启动参数改为--illegal-access=deny。并继续分析日志,以确保代码中没有反射失败的情况。

将运行时JDK改为JDK17

我们的策略是:

  1. 先将测试环境RunTime JDK改为17并运行一段时间;如果测试环境运行稳定,则将产品环境RunTime JDK改为逐渐切换为17
  2. 但使用Jenkins build项目时,编译时JDK依旧保持JDK11
  3. 简而言之,把JDK11编译出来的包放在JDK17中跑

优化Build Java应用时的Jenkins Job

目前build java应用之后,tomcat使用的JDK是hard code在相关的jenkins job里的。

这种写法不利于当前以及后续JDK升级的测试。原因是:这些jenkins job的配置基本由devops维护,我们实际使用者如果有什么需求只需要给他们提就可以了,他们会给我们创建单独的job。

在了解了他们的实际工作过程之后,我发现完全没必要copy、创建新的jenkins job,只需要在原有的jenkins job上添加一个参数,例如:RUNTIME_JDK,build项目时将该参数传给shell脚本,在构建完docker镜像之后,启动Tomcat之前,执行一个switchJDK.sh 即可完成JDK的切换。

这样做的好处是

  1. 从长期来讲,devops的工作量反而是减轻了且有助于他们的代码维护,他们只需要定期把未来要使用JDK版本纳入到我们使用的自动以的docker镜像中,就无需介入JDK的升级工作。
  2. 对于我们实际升级JDK的人以及其他开发或QA同事来说,有了这个参数,前期JDK升级时,如果测试环境有什么问题,可以迅速切换回正在使用的JDK,不会影响当前工单的smoke test。

将编译时JDK改为JDK17

产品环境运行时JDK改为17之后,运行一段时间,如果产品环境稳定。则将编译时JDK改为JDK17。这一步主要是pom.xml的改变

<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

这个改变合并到主分支之后,build该项目的jenkins job需要同时做切换。指定编译时JDK为17

通知开发切换为JDK17

上述改动合并到主分支之后,JDK就完成了升级,需要通知开发下载和产品、测试环境一样的JDK 版本并切换,并修改IDEA中有关Java版本、编译的配置

写在最后

对所有Java应用,从JDK8到JDK11,所有的验证、测试、分批部署到产品、最终完成升级,我们用了接近半年时间完成升级。预计JDK17会比较顺利,可能4个月左右完成升级。

上面这些事情看起来不复杂,但整个过程要想保证对服务不造成影响,需要我们非常细心、谨慎,以及和其他团队充分配合才能一起完成这件事,这更考验我们除了编程之外的技能。

最后以一句话结尾:

只有那些有耐心做好简单事情的人,才能获得轻松完成困难事情的技能 ​​​

相关文章:

  • UE5蓝图设置界面尺寸大小
  • 【小工具】定时任务执行器
  • CUDA编程高阶优化:如何突破GPU内存带宽瓶颈的6种实战策略
  • 深入详解MYSQL的MVCC机制
  • 第一章 教育与教育学
  • 提权实战!
  • Python 基础语法汇总
  • 数据运营与数据分类
  • CPU(中央处理器)
  • 28.[MRCTF2020]Xor1(保姆教程)
  • 基于PySide6与pycatia的CATIA绘图比例智能调节工具开发全解析
  • [Dify] Dify 本地部署及连接 Ollama 模型全流程指南
  • Deepseek IP-Adapter与InstantID的区别
  • 计算机系统概论
  • CS5346 - Visualization Design Process
  • 泛型的二三事
  • oracle DECODE 函数
  • DeeplxFile相关文件下载
  • 七、自动化概念篇
  • Elasticsearch 故障转移及水平扩容
  • 企业不想做网站的原因/谷歌seo优化推广
  • 吉安市网站建设/如何优化网络连接
  • 网站开发项目背景/微商软文范例大全100
  • cdr里做网站超级链接/网络优化工具
  • 小公司如何做网站/网站排名优化方案
  • 什么网站做二维码比较好/百度关键词点击工具