保姆级升级 java17 指南,建议收藏
共 5145字,需浏览 11分钟
·
2021-10-03 06:05
一、前言
Java 17,一个长期支持 (LTS) 版本已经发布半个多月。不幸的是,许多应用程序仍在旧版本的 Java 上运行,例如以前的 LTS 版本:Java 8 和 Java 11。本文解释了你应该升级应用程序的原因,并帮助你实际升级到 Java 17。
但首先,许多人都可能会问:“为什么要升级?”
java9 紧凑字符串(更加节省内存) java11 httpclient java12 switch 表达式(简化代码) java13 多行文本 java14 record,匹配模式(简化代码) 等等...
随着 Java 版本迭代,GC 得到大量优化,相对于老版本更快并且节省内存。仅仅靠升级 Java 版本就可以为我们带来众多收益。
二、在 Java 升级期间需要更改什么?
你的应用程序包含你和你的团队编写的代码,并且可能还包含依赖项。如果从 JDK 中删除了某些内容,则可能会破坏代码、依赖项或两者。通常有助于确保这些依赖项是最新的,以解决这些问题。有时,你可能需要等到框架发布与最新 Java 版本兼容的新版本,然后才能开始升级过程。这意味着作为升级前评估过程的一部分,你对你使用的依赖项需要有很好的了解。
大多数功能不会一次性从 JDK 中全部删除。首先,功能被标记为弃用。例如,用于 XML 绑定的 Java 架构 (JAXB) 在 Java 9 中被标记为弃用,然后在 Java 11 中才被删除。如果你一直在更新,那么你会知道弃用,并且你可以在功能被删除之前解决这些问题。但是,如果你直接从 Java 8 跳到 Java 17,那么可能会踩到很多坑。
要查看 API 更改,例如,查看特定 Java 版本中哪些方法被删除或添加到 String API 中,请查看 Marc Hoffmann 和 Cay Horstmann 撰写的 The Java Version Almanac。
三、多版本 JAR 功能
如果你的基础组件任然被使用在旧的 JDK并且在他们的站点上升级不受你的控制怎么办?Java 9 和 JEP 238 中引入的多版本 JAR 功能可能很有用,因为它允许你将多个 Java 版本(包括早于 Java 9 的版本)的代码打包在一个 JAR 文件中。
例如:创建一个 Application 类(清单 1)和一个 Student 类(清单 2)并将它们放在文件夹 src/main/java/com/example 中,Student 类在 Java 8 上运行。
清单 1. Application class
public class Application {
public static void main(String[] args) {
Student student = new Student("James ");
System.out.println("Implementation " + student.implementation());
System.out.println("Student name James contains a blank: " + student.isBlankName());
}
}
清单 2. Student class for Java 8
public class Student {
final private String firstName;
public Student(String firstName) {
this.firstName = firstName;
}
boolean isBlankName() {
return firstName == null || firstName.trim().isEmpty();
}
static String implementation() { return "class"; }
}
接下来,创建一个 Student record(清单 3),它不仅使用了 record(Java 14 中引入)而且还使用了 String.isBlank() 方法(Java 11 中引入),并将其放在 src/main/java17/com/example
文件夹。
清单 3. 使用新语法的 Student record
public record Student(String firstName) {
boolean isBlankName() {
return firstName.isBlank();
}
static String implementation() { return "record"; }
}
根据你使用的构建工具,需要一些配置。Maven 示例可以在我的 GitHub repository 中找到。该示例基于 Java 17 构建并创建 JAR 文件。在 JDK 17 或更高版本上执行 JAR 文件时,将使用学生记录。在旧版本上执行 JAR 文件时,将使用 Student 类。
当然你也可以参考 https://github.com/xkcoding/simple-http,笔者给它 pr 了 java11 下的 HttpClient 支持,该工具使用 Java8 编译。
此功能非常有用,例如,如果新 API 提供更好的性能,因为你可以为拥有最新 Java 版本的客户使用这些 API。相同的 JAR 文件可用于使用较旧 JDK 的客户,而不会提高性能。
请注意,所有实现(在本例中为 Student
)都应具有相同的公共 API 以防止运行时问题。不幸的是,构建工具不会验证公共 API,但一些 IDE 会验证。另外,在 JDK 17 中,你可以使用 jar –validate
命令来验证 JAR 文件。
需要注意的是某些版本的 JDK 中存在预览功能。一些更大的特性首先作为预览发布,并且可能会在下一个 JDK 之一中产生最终特性。这些预览功能同时存在于 Java 的 LTS 和非 LTS 版本中。这些功能使用 enable-preview
标志启用,默认情况下关闭。如果你在生产代码中使用这些预览功能,请注意它们可能会在 JDK 版本之间发生变化,这可能会导致需要将代码进行一些调试或重构。
四、有关 Java 弃用和删除的功能
在升级 JDK 之前,请确保你的 IDE、构建工具和依赖项是最新的。Maven Versions Plugin 和 Gradle Versions Plugin 显示你拥有哪些依赖项并列出最新的可用版本。
请注意,这些工具仅显示你使用的依赖的新版本——但有时依赖的名称会发生变化、分叉或代码移动。例如:JAXB 最初是通过 javax.xml.bind:jaxb-api
提供的,但在它过渡到 Eclipse Foundation 后更改为 jakarta.xml.bind:jakarta.xml.bind-api
。要查找此类更改,你可以使用 Jonathan Lermitage 的 Old GroupIds Alerter plugin for Maven 或他的 plugin for Gradle。
JavaFX. 从 Java 11 开始,不再包含 JavaFX 作为规范的一部分,并且大多数 JDK 版本已将其删除。你可以使用来自 Gluon 的单独构建的 JavaFX 或将 OpenJFX 依赖项添加到你的项目。
Fonts. 曾几何时,JDK 包含一些字体,但从 Java 11 开始,它们被删除了。例如:如果你使用 Apache POI(Microsoft Office 兼容文档的 Java API),你将需要字体。操作系统需要提供字体,因为它们不再存在于 JDK 中。但是,在 Alpine Linux 等操作系统上,必须使用 apt install fontconfig
命令手动安装字体。根据你使用的字体,可能需要额外的包。
Java Mission Control. 这是一个非常有用的工具,用于监视和分析你的应用程序。强烈建议你了解一下。Java Mission Control 曾经包含在 JDK 中,但现在改了名并且需要单独下载:JDK Mission Control。
Java EE. JDK 11 中最大的变化是删除了 Java EE 模块。许多应用程序都依赖 Java EE 模块,例如:前面提到的 JAXB。由于这些模块不再存在于 JDK 中,因此你需要添加相关的依赖项。表格 1 列出了各种模块及其依赖项。请注意,JAXB 和 JAX-WS 都需要两个依赖项:一个用于 API,另一个用于实现。另一个变化是命名约定,因为 Java EE 由 Eclipse 基金会以 Jakarta EE 的名义进行维护。你的包导入可能需要调整,较新版本的 Jakarta EE 使用 jakarta.xml.bind.*
而不是 javax.xml.bind.*
。
表格 1. Java EE 模块和当前的替代品
CORBA. Java 的 CORBA 模块没有官方替代品,该模块在 Java 11 中被删除。但是 Oracle GlassFish Server 包含了 CORBA 的实现。
Nashorn. Java 15 删除了 Nashorn JavaScript 引擎。如果仍想使用它,你可以添加 nashorn-core 依赖。
org.openjdk.nashorn
nashorn-core
15.3
Experimental compilers. Java 17 删除了对 GraalVM 的实验性提前 (AOT) 和即时 (JIT) 编译器的支持,详见 JEP 410。
五、寻找不受支持的文件
你可能会遇到 Unsupported class file major version 61
这样的错误。我已经在 JaCoCo 代码覆盖库和各种其他 Maven 插件中看到了它。消息中版本 61 指的是 Java 17。因此,在这种情况下,这意味着你使用的框架或工具的版本不支持 Java 17。因此,你应该将框架或工具升级到 新版本。
六、JDK 内部 API
Java 16 和 Java 17 封装了 JDK 内部 API,这会影响 Lombok 等各种框架。你可能会看到诸如 module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module
,这意味着你的应用程序无法再访问 JDK 的这些内部 API。
通常,我建议升级所有使用这些内部结构的依赖项,并确保你自己的代码不再使用 JDK 的内部 API。
如果这是不可能的,有一个变通方法仍然使你的应用程序能够访问内部。例如,如果你需要访问 comp
模块,请使用以下命令:
--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
但是,这只是解决问题的最后手段,最好还是停止使用这些内部 API,因为你正在绕过 Java 团队添加的重要保护措施。
关于此问题更多详细信息可查看 Java 16 的 JEP 396 和 Java 17 的 JEP 403。
七、结论
升级依赖项和为 JDK 已经删除的功能找到替代方案就可以避免大部问题。我推荐一种结构化的方法来逐步升级:首先,确保代码可以编译,然后运行测试,然后运行应用程序。
如果你可以告诉自己、你的团队和你的公司,你可以在 JDK 17 上编译和测试所有内容,而不必告诉他们几乎已经完成,或者更糟糕的是,它只完成了 80%,那么迁移过程就会好得多。
笔者开源的微服务组件 mica 已经适配 java17,mybatis-plus 新版也已经支持。目前笔者已经有一部分服务升级到 Java17,很丝滑,如果你有升级 Java 的想法,不妨直接升级到 Java17。
关注 JAVA架构日记,学习技术不迷路!