多版本发布 JAR(Multi-release JAR)特性是在 Java 9 中引入的。这一特性允许使用多个版本的类来适应 Java 的不同版本。例如,许多第三方库或框架都是基于 Java 构建的。随着 Java 语言的不断演进,每次主要版本更新都会给语言添加许多新功能。为了兼容这些新功能,第三方库/框架需要重写其代码库,这让团队非常不愿意采用新功能。这对它们来说是一个阻碍,使得它们难以迁移到 Java 的新版本。
为了应对维护同一文件的多个源代码版本或特定平台版本的问题,引入了多版本发布 JAR 特性。考虑以下示例:
典型的 JAR 文件结构
一个典型的 JAR 文件会在根级别包含所有的类。
jar root
- Calculator.class
- Util.class
- Math.class
- Service.class
如果有一个针对 Java 9 特性的 Util
类,那么这个 JAR 文件就不能在 Java 8 或更低版本的环境中使用。
多版本发布 JAR 解决方案
在多版本发布的 JAR 文件中,格式已经被增强,可以维护和使用适用于不同平台的不同版本的 Java 类或资源。在 JAR 文件中,MANIFEST.MF
文件在其主要部分有一个条目 Multi-Release: true
。META-INF
目录也包含一个名为 versions
的子目录,其下级目录(以 9 表示 Java 9)存储版本特定的类和资源文件。
利用 MANIFEST.MF
文件,我们可以将 Java 9 或更高版本特定的类放置在不同的位置,如下所示:
Java Multi-Release Jar Files Directory Structure
jar root
- Calculator.class
- Util.class
- Math.class
- Service.class
META-INF
- versions
- 9
- Util.class
- Math.class
- 10
- Util.class
- Math.class
如果 JRE 不支持多版本发布的 JAR 文件,那么它会选择根级别的类进行加载和执行;否则,将加载特定版本的类。例如,如果上述 JAR 文件在 Java 8 中使用,那么将会使用根级别的 Util.class
。如果在同一 JRE 下执行,JRE 是 Java 9,那么将会选择 Java 9 版本特定的类,依此类推。这样,第三方库/框架可以在不改变其针对较低版本编写的源代码的情况下支持新功能。
创建和使用多版本发布的 JAR 文件
在这个例子中,我们将创建并使用一个多版本发布的 JAR 文件,包含两个版本的 Tester.java
文件,一个针对 JDK 7,另一个针对 JDK 9,并在不同版本的 JDK 上运行它。
以下是创建和使用多版本发布的 JAR 文件的步骤:
步骤 1:创建针对 Java 7 的 Java 类
让我们创建一个具有 Java 7 特定代码和特性的 Java 类,这些在 Java 9 之前是不可用的。在这个例子中,我们仅仅是打印一条消息来展示这个特性的使用。
创建一个文件夹 c:/test/java7/com/tutorialspoint
。创建 Tester.java
并包含以下内容:
Tester.java
这是一个简单的代码,在程序执行时打印一条 Java 7 特定的消息。
package com.tutorialspoint;
public class Tester {
public static void main(String[] args) {
System.out.println("Inside java 7");
}
}
步骤 2:创建针对 Java 9 的 Java 类
让我们创建一个具有 Java 9 增强特性和功能的 Java 类,这些在 Java 9 之前是不可用的。在这个例子中,我们同样是打印一条消息来展示这个特性的使用。
创建一个文件夹 c:/test/java9/com/tutorialspoint
。创建 Tester.java
并包含以下内容:
Tester.java
这也是一段类似的代码,在程序执行时打印一条 Java 9 特定的消息。
package com.tutorialspoint;
public class Tester {
public static void main(String[] args) {
System.out.println("Inside java 9");
}
}
为了使用多版本发布的 JAR 特性,必须确保两个类的签名相同。公共接口如方法签名在两个类中应该是相同的。
步骤 3:使用目标版本编译
C:\test > javac --release 9 java9/com/tutorialspoint/Tester.java
C:\JAVA > javac --release 7 java7/com/tutorialspoint/Tester.java
步骤 4:创建一个多版本发布的 JAR 文件
C:\JAVA > jar -c -f test.jar -C java7 . --release 9 -C java9 .
Warning: entry META-INF/versions/9/com/tutorialspoint/Tester.java,
multiple resources with same name
步骤 5:使用 JDK 7 运行 JAR 文件
C:\JAVA > java -cp test.jar com.tutorialspoint.Tester
Inside Java 7
步骤 6:使用 JDK 9 运行 JAR 文件
C:\JAVA > java -cp test.jar com.tutorialspoint.Tester
Inside Java 9
结论
我们可以看到,通过多版本发布的 JAR 特性,我们可以在没有向后兼容性问题的情况下创建一个类的多个版本。我们展示了同样的命令可以用于执行一个类。根据列在 META-INF
文件中的 JRE 版本,将选择相应的类。对于较低版本的 JRE,如果它们不支持多版本发布的 JAR 文件,将选择根级别的类而不是版本特定的类。最后,版本化类的公共方法签名应该相同,这样此功能才能完美工作。