Java 9 新特性 - 多版本共存 JAR
Java 9 之前的 JAR 格式中只能包含一个 Java 版本,显然,这是不符合 Java 这种开启了版本帝的发展线路了,想想,现在大多数 Java 还停留在 Java 6 7 8 的年代,Java 10 已经发布,如果要发布一个 JAR 格式的类库,意味着要编译多个版本的 JAR, 6 7 8 9 10 五个版本,看起来也太恐怖了。
Java 9 突然间良心发现,开始支持多版本共存的 JAR 了。
Java 9 引入了一个新的功能,其实也不算吧,就是增强了 JAR 格式,可以在同一个 JAR 中维护和使用不同版本的 java 类或资源
JAR 多版本共存原理
首先在 JAR 中,文件 MANIFEST.MF 文件的 main 节中有一个条目 Multi-Release:true , 用于指定该 JAR 包是多 Java 版本共存的
同时,JAR 目录下的子目录 META-INF 还包含一个 versions 子目录,其子目录 ( 从 9 开始,用于 Java 9 ) 存储特定于版本的类和资源文件
多版本 JAR 范例
接下来这个范例,我们的多版本 JAR 中有三个版本的 MultiReleaseJarTester.java 文件,一个用于 JDK 8,一个用于 JDK 9,最后一个用于 JDK 10 并在可以在这些不同的 JDK 版本上运行
- 
首先,我们在当前工作目录,例如我的是 d:\devops\java9创建一个multireleasejar文件然后创建一个目录 src/main目录,并在该目录中创建java10目录并在 java10 目录中创建 cn/twle包创建完成后,目录结果如下 . └── src └── main ├── java10 └── cn └── twle
- 
然后在 java10/cn/twle目录下新建MultiReleaseJarTester.java文件并输入以下内容package cn.twle; public class MultiReleaseJarTester { public static void main(String[] args) { String javaVersion = System.getProperty("java.version"); System.out.println("JDK version is:" + javaVersion); } } 创建完成后目录结构如下 . └── src └── main ├── java10 └── cn └── twle └── MultiReleaseJarTester.java
- 
然后重复 2-3 步骤,创建相同的目录 java9和java8,内容都是一样的,创建完成后目录结构如下. └── src └── main ├── java10 │ └── cn │ └── twle │ └── MultiReleaseJarTester.java ├── java8 │ └── cn │ └── twle │ └── MultiReleaseJarTester.java └── java9 └── cn └── twle └── MultiReleaseJarTester.java
- 
跳转到 multireleasejar目录,并使用下面的命令编译三个不同的版本,其中,最重要的参数是--releasejavac --release 10 -d java10 src/main/java10/cn/twle/MultiReleaseJarTester.java javac --release 9 -d java9 src/main/java9/cn/twle/MultiReleaseJarTester.java javac --release 8 -d java8 src/main/java8/cn/twle/MultiReleaseJarTester.java --release选项用于指定要编译目标的 JDK 版本。编译完成后就可以看到 multireleasejar的目录结构如下. ├── java10 │ └── cn │ └── twle │ └── MultiReleaseJarTester.class ├── java8 │ └── cn │ └── twle │ └── MultiReleaseJarTester.class ├── java9 │ └── cn │ └── twle │ └── MultiReleaseJarTester.class └── src └── main ├── java10 │ └── cn │ └── twle │ └── MultiReleaseJarTester.java ├── java8 │ └── cn │ └── twle │ └── MultiReleaseJarTester.java └── java9 └── cn └── twle └── MultiReleaseJarTester.java
- 
然后我们就可以使用下面的命令将这些不同版本的 MultiReleaseJarTester.class 封装到一个 JAR 里 - 
首先跳转到 multireleasejar目录,然后运行下面的命令首先创建一个默认版本,也就是 Java 8 版本jar -c -f multireleasejar.jar --main-class=cn.twle.MultiReleaseJarTester -C java8 . 运行完成后,就可以在当前目录看到一个 multireleasejar.jar文件我们可以使用 jar -tvf multireleasejar.jar查看文件中的内容[yufei@www.twle.cn multireleasejar]$ jar -tvf multireleasejar.jar 0 Sun Sep 02 11:19:00 CST 2018 META-INF/ 109 Sun Sep 02 11:19:00 CST 2018 META-INF/MANIFEST.MF 0 Sun Sep 02 10:51:40 CST 2018 cn/ 0 Sun Sep 02 10:51:40 CST 2018 cn/twle/ 714 Sun Sep 02 10:51:40 CST 2018 cn/twle/MultiReleaseJarTester.class
- 
然后依次运行下面的命令添加两个其它的版本 jar -u -f multireleasejar.jar --release 10 -C java10 . jar -u -f multireleasejar.jar --release 9 -C java9 . 执行第二条语句的时候会有一个警告,可以忽略 [yufei@www.twle.cn multireleasejar]$ jar -u -f multireleasejar.jar --release 9 -C java9 . 警告: 条目 META-INF/versions/10/cn/twle/MultiReleaseJarTester.class 包含与 jar 中的 现有条目相同的类 
 
- 
好了,这样我们的多版本 multireleasejar.jar 就生成了,然后使用 jar -tvf multireleasejar.jar 查看文件中的内容如下
[yufei@www.twle.cn multireleasejar]$ jar -tvf multireleasejar.jar 
     0 Sun Sep 02 11:20:24 CST 2018 META-INF/
   130 Sun Sep 02 11:20:40 CST 2018 META-INF/MANIFEST.MF
     0 Sun Sep 02 10:51:40 CST 2018 cn/
     0 Sun Sep 02 10:51:40 CST 2018 cn/twle/
   714 Sun Sep 02 10:51:40 CST 2018 cn/twle/MultiReleaseJarTester.class
     0 Sun Sep 02 10:21:20 CST 2018 META-INF/versions/10/
     0 Sun Sep 02 10:21:20 CST 2018 META-INF/versions/10/cn/
     0 Sun Sep 02 10:21:20 CST 2018 META-INF/versions/10/cn/twle/
   956 Sun Sep 02 10:21:20 CST 2018 META-INF/versions/10/cn/twle/MultiReleaseJarTester.class
     0 Sun Sep 02 10:22:06 CST 2018 META-INF/versions/9/
     0 Sun Sep 02 10:22:06 CST 2018 META-INF/versions/9/cn/
     0 Sun Sep 02 10:22:06 CST 2018 META-INF/versions/9/cn/twle/
   956 Sun Sep 02 10:22:06 CST 2018 META-INF/versions/9/cn/twle/MultiReleaseJarTester.class
运行多版本 JAR 包
首先在 Java 10 的环境下运行,输出结果如下
[yufei@www.twle.cn multireleasejar]$ 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) [yufei@www.twle.cn multireleasejar]$ java -jar multireleasejar.jar JDK version is:10.0.2
其次,在 Java 8 中运行,输出结果如下
[yufei@www.twle.cn multireleasejar]$ java -version java version "1.8.0_45" Java(TM) SE Runtime Environment (build 1.8.0_45-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode) [yufei@www.twle.cn multireleasejar]$ java -jar multireleasejar.jar JDK version is:1.8.0_45
注意
- 
首先,没必要特别区分 src/main/java10、src/main/java9、src/main/java8这几个目录,如果代码都相同,只要一份即可
- 
其次,多版本真正最重要的是编译的时候带上 --release [version]版本号,用来指定编译版本
- 
打包成 jar的时候,三条命令可以放在一起,但最重要的是--release [version]一定要在-C参数之前,如果在之后,则有可能无效我折腾好久,就是因为犯了这个默认错误 
- 
一定要存在一个默认版本,一般情况下,可以使用主流版本为默认版本,这个默认版本可以不用添加 --release参数