多版本共存的JAR(Java Archive)文件是Java 9引入的一个新特性,它允许在同一个JAR文件中维护和使用不同版本的Java类或资源。这种特性使得开发者能够创建一个JAR包,该包可以在多个Java版本上运行,而无需为每个Java版本提供单独的JAR包。

接下来这个示例,我们的多版本JAR中有三个版本的MultiJarDemo.java文件,一个用于JDK8,一个用于JDK9,最后一个用于 JDK10,并在可以在这些不同的JDK版本上运行。

准备目录

首先我们准备一个工作目录,我这里叫multi-jar-demo,目录结构如下:

.
└── src
    └── main
        ├── java10
        │   └── com
        │       └── morris
        │           └── MultiJarDemo.java
        ├── java8
        │   └── com
        │       └── morris
        │           └── MultiJarDemo.java
        └── java9
            └── com
                └── morris
                    └── MultiJarDemo.java

java8、java9、java10目录下都一个MultiJarDemo.java,包名也一样。

源码

java8下的MultiJarDemo.java内容如下:

package com.morris;

/**
 * 多版本jar,8版本
 */
public class MultiJarDemo {
    public static void main(String[] args) {
        String javaVersion = System.getProperty("java.version");
        System.out.println("JDK version is:" + javaVersion + ", classVersion: 8");
    }
}

java9下的MultiJarDemo.java内容如下:

package com.morris;

/**
 * 多版本jar,9版本
 */
public class MultiJarDemo {
    public static void main(String[] args) {
        String javaVersion = System.getProperty("java.version");
        System.out.println("JDK version is:" + javaVersion + ", classVersion: 9");
    }
}

java10下的MultiJarDemo.java内容如下:

package com.morris;

/**
 * 多版本jar,10版本
 */
public class MultiJarDemo {
    public static void main(String[] args) {
        String javaVersion = System.getProperty("java.version");
        System.out.println("JDK version is:" + javaVersion + ", classVersion: 10");
    }
}

编译

multi-jar-demo目录下,并使用下面的命令编译三个不同版本的class文件,其中,最重要的参数是–release;

$ javac --release 8  -d java8   src/main/java8/com/morris/MultiJarDemo.java

$ javac --release 9  -d java9   src/main/java9/com/morris/MultiJarDemo.java

$ javac --release 10  -d java10   src/main/java10/com/morris/MultiJarDemo.java

--release选项用于指定要编译目标的JDK版本。

编译完成后就可以看到multi-jar-demo的目录结构如下:

.
├── java10
│   └── com
│       └── morris
│           └── MultiJarDemo.class
├── java8
│   └── com
│       └── morris
│           └── MultiJarDemo.class
├── java9
│   └── com
│       └── morris
│           └── MultiJarDemo.class
└── src
    └── main
        ├── java10
        │   └── com
        │       └── morris
        │           └── MultiJarDemo.java
        ├── java8
        │   └── com
        │       └── morris
        │           └── MultiJarDemo.java
        └── java9
            └── com
                └── morris
                    └── MultiJarDemo.java

20 directories, 6 files

打包

然后我们就可以使用下面的命令将这些不同版本的MultiJarDemo.class封装到一个JAR里。

首先跳转到multi-jar-demo目录下目录,然后运行下面的命令首先创建一个默认版本,也就是Java8版本;

$ jar -c -f  multi-jar-demo.jar --main-class=com.morris.MultiJarDemo -C j
ava8 .

一定要存在一个默认版本,一般情况下,可以使用主流版本为默认版本,这个默认版本可以不用添加–release参数。

运行完成后,就可以在当前目录看到一个multi-jar-demo.jar文件,我们可以使用jar -tvf multi-jar-demo.jar来查看文件中的内容:

$ jar -tvf multi-jar-demo.jar
     0 Tue Mar 19 11:14:56 CST 2024 META-INF/
   103 Tue Mar 19 11:14:56 CST 2024 META-INF/MANIFEST.MF
     0 Tue Mar 19 11:01:40 CST 2024 com/
     0 Tue Mar 19 11:01:40 CST 2024 com/morris/
   727 Tue Mar 19 11:01:40 CST 2024 com/morris/MultiJarDemo.class

然后依次运行下面的命令添加两个其它的版本:

$ jar -u -f  multi-jar-demo.jar --release 9 -C java9 .

$ jar -u -f  multi-jar-demo.jar --release 10 -C java10 .

好了,这样我们的多版本multi-jar-demo.jar就已经打包完成了,然后使用jar -tvf multi-jar-demo.jar来查看文件中最终的内容:

$ jar -tvf multi-jar-demo.jar
     0 Tue Mar 19 11:14:56 CST 2024 META-INF/
   124 Tue Mar 19 11:25:56 CST 2024 META-INF/MANIFEST.MF
     0 Tue Mar 19 11:01:40 CST 2024 com/
     0 Tue Mar 19 11:01:40 CST 2024 com/morris/
   727 Tue Mar 19 11:01:40 CST 2024 com/morris/MultiJarDemo.class
     0 Tue Mar 19 11:06:26 CST 2024 META-INF/versions/10/
     0 Tue Mar 19 11:06:26 CST 2024 META-INF/versions/10/com/
     0 Tue Mar 19 11:06:26 CST 2024 META-INF/versions/10/com/morris/
   959 Tue Mar 19 11:06:26 CST 2024 META-INF/versions/10/com/morris/MultiJarDemo.class
     0 Tue Mar 19 11:01:46 CST 2024 META-INF/versions/9/
     0 Tue Mar 19 11:01:46 CST 2024 META-INF/versions/9/com/
     0 Tue Mar 19 11:01:46 CST 2024 META-INF/versions/9/com/morris/
   958 Tue Mar 19 11:01:46 CST 2024 META-INF/versions/9/com/morris/MultiJarDemo.class

运行

在Java10的环境下运行,输出结果如下:

$ java -version
java version "10.0.2" 2018-07-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.2+13)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.2+13, mixed mode)

$ java -jar multi-jar-demo.jar
JDK version is:10.0.2, classVersion: 10

在Java9的环境下运行,输出结果如下:

$ java -version
java version "9.0.4"
Java(TM) SE Runtime Environment (build 9.0.4+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)

$ java -jar multi-jar-demo.jar
JDK version is:9.0.4, classVersion: 9

在Java8的环境下运行,输出结果如下:

$ java -version
java version "1.8.0_401"
Java(TM) SE Runtime Environment (build 1.8.0_401-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.401-b10, mixed mode)

$ java -jar multi-jar-demo.jar
JDK version is:1.8.0_401, classVersion: 8

最后,尽管多版本共存的JAR为Java应用程序带来了更大的灵活性,但它并不能解决所有版本冲突问题。在某些情况下,你可能需要使用其他工具或策略(如类加载器隔离、OSGi等)来处理复杂的版本冲突问题。

【java9】java9新特性之多版本共存JAR_jdk