Java SE 9 多版本兼容 JAR 包示例
Java SE 9 多版本兼容 JAR 包示例
作者:Grey
说明
Java 9 版本中增强了Jar 包多版本字节码文件格式支持,也就是说在同一个 Jar 包中我们可以包含多个 Java 版本的 class 文件,这样就能做到 Jar 包升级到新的 Java 版本时不用强迫使用方为了使用新 Jar 包而升级自己的业务模块 Java 版本,也不用针对不同最低支持 Java 版本提供不同的 Jar,真正的做到了一个 Jar 包兼容所有的目的。
本文通过以下示例来说明多版本 Jar 包的使用。
环境准备
机器上应该有多个版本的 JDK 用于测试,并且至少有一个是 JDK 9 或者更高版本。
命令行编译示例
注:本示例无需使用 IDE ,我们用最原始的方式创建一个多版本的 Jar 包。
新建一个文件夹,用项目名称命名,并且在其中把src目录,包名都建好,可以自定义,后续编译命令自行调整即可。

src\main\java\git\snippet目录下存的是旧版本 JDK 编写的代码。在这个目录下新建两个类。
package git.snippet;
/**
* Java SE 9 Multi-Release JAR Files示例
*
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/8/14
* @since 9
*/
public class App {
public static void main(String[] args) {
Helper.hello(args[0]);
}
}
package git.snippet;
/**
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/8/14
* @since 1.7
*/
public class Helper {
public static void hello(String name) {
// jdk 9+不能用_作为变量
String _ = "hello";
System.out.println(_ + ", " + name);
}
}
src\main\java9\git\snippet目录下存的是新版本 JDK 编写的代码。我们需要把Helper类用新的 JDK 版本特性来实现。代码如下
package git.snippet;
/**
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/8/14
* @since 9
*/
public class Helper {
public static void hello(String name) {
// 旧版本用_作为变量,jdk9不能用_作为变量
String fixName = "hello";
System.out.println(fixName + ", " + name + " from jdk9");
}
}
创建好上述类以后,项目结构如下

接下来是编译,在项目目录下,用 JDK 9+的javac执行如下两个编译命令
C:\jdk\jdk-11\bin\javac --release 7 -d classes src\main\java\git\snippet\*.java
提示信息如下(仅显示了警告)
D:\git\hello-mrjar>C:\jdk\jdk-11\bin\javac --release 7 -d classes src\main\java\git\snippet\*.java
src\main\java\git\snippet\Helper.java:11: 警告: 从发行版 9 开始, '_' 为关键字, 不能用作标识符
String _ = "hello";
^
src\main\java\git\snippet\Helper.java:12: 警告: 从发行版 9 开始, '_' 为关键字, 不能用作标识符
System.out.println(_ + ", " + name);
^
2 个警告
C:\jdk\jdk-11\bin\javac --release 9 -d classes-9 src\main\java9\git\snippet\*.java
无提示信息和报错信息。
接下来是通过 JDK 9+ 的jar进行打包,打包的时候,运行如下打包命令
C:\jdk\jdk-11\bin\jar --create --file target/hello-mrjar.jar --main-class git.snippet.App -C classes . --release 9 -C classes-9 .
如果提示如下报错信息
java.nio.file.NoSuchFileException: C:\Users\zhuiz\AppData\Local\Temp\hello-mrjar.jar9462053262887373909.jar -> target\hello-mrjar.jar
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
at java.base/sun.nio.fs.WindowsFileCopy.move(WindowsFileCopy.java:395)
at java.base/sun.nio.fs.WindowsFileSystemProvider.move(WindowsFileSystemProvider.java:292)
at java.base/java.nio.file.Files.move(Files.java:1422)
at jdk.jartool/sun.tools.jar.Main.validateAndClose(Main.java:466)
at jdk.jartool/sun.tools.jar.Main.run(Main.java:349)
at jdk.jartool/sun.tools.jar.Main.main(Main.java:1681)
则手动在项目目录下建立一个target文件夹,再次执行打包命令,错误解决。
在target目录下,包已经打好hello-mrjar.jar。
最后进行测试,用JDK 9之前的java来执行这个jar包。
C:\jdk\jdk1.8\bin\java -jar hello-mrjar.jar Grey
输出如下
hello, Grey
用 JDK 9+ 的java来执行这个jar包。
C:\jdk\jdk-11\bin\java -jar hello-mrjar.jar Grey
输出如下
hello, Grey from jdk9
这样就实现了同一个 Jar 包中包含多个 Java 版本的 class 文件,用不同版本 JDK 执行的时候,运行不同版本的 class 文件。
也可以使用Intellij IDEA来创建多版本 Jar,这里是参考文档:Creating Multi-Release JAR Files in IntelliJ IDEA
Maven 项目配合多版本 Jar 示例
多数情况下,我们不会手动创建项目目录并编译,一般用 Maven 来管理项目。本示例演示如何在 Maven 下进行多版本 Jar 包的管理。
创建一个 Maven 项目,结构如下

和上例类似,src\main\java9文件夹中是对应的新版本 JDK 的代码
src\main\java文件夹中是对应的旧版本的 JDK 代码。
代码清单如下
package git.snippet;
public class App {
public static void main(String[] args) {
System.out.println(String.format("Running on %s", new DefaultVersion().version()));
}
}
旧版本代码,放在src\main\java对应的包下。
package git.snippet;
public class DefaultVersion {
public String version() {
System.out.println("use jdk");
return System.getProperty("java.version");
}
}
新版本代码,放在src\main\java9对应的包下。
package git.snippet;
public class DefaultVersion {
public String version() {
System.out.println("use jdk 9+");
return Runtime.version().toString();
}
}
pom.xml文件配置,注意,相关的文件夹或者包有调整,需要做对应的调整。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>git.snippet</groupId>
<artifactId>hello-mrjar-with-maven</artifactId>
<version>1.0</version>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile-java-8</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compileSourceRoots>
<!---旧版本代码的位置-->
<compileSourceRoot>${project.basedir}/src/main/java</compileSourceRoot>
</compileSourceRoots>
</configuration>
</execution>
<execution>
<id>compile-java-9</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>9</release>
<compileSourceRoots>
<!---新版本代码的位置-->
<compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
</compileSourceRoots>
<outputDirectory>${project.build.outputDirectory}/META-INF/versions/9</outputDirectory>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<skip>true</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
<manifest>
<!--设置主方法入口-->
<mainClass>git.snippet.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
然后用新版本的 JDK 进行打包,在项目目录下执行
mvn clean package -Dmaven.test.skip=true
提示
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ hello-mrjar-with-maven ---
[INFO] Building jar: D:\git\hello-mrjar-with-maven\target\hello-mrjar-with-maven-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.447 s
[INFO] Finished at: 2022-08-15T11:29:48+08:00
[INFO] ------------------------------------------------------------------------
说明打包成功。然后进入target目录,进行验证
用旧版本的 Java 执行 Jar 包
C:\jdk\jdk1.8\bin\java -jar hello-mrjar-with-maven-1.0.jar
输出
use jdk
Running on 1.8.0_202
用新版本的 Java 执行 Jar 包
C:\jdk\jdk-11\bin\java -jar hello-mrjar-with-maven-1.0.jar
输出
use jdk 9+
Running on 11.0.15+8-LTS-149
代码
参考资料
Multi-Release JAR Files with Maven
JEP 238: Multi-Release JAR Files
Java SE 9 多版本兼容 JAR 包示例的更多相关文章
- java9新特性-6-多版本兼容jar包
1.官方Feature 238: Multi-Release JAR Files 2.使用说明 当一个新版本的Java出现的时候,你的库用户要花费数年时间才会切换到这个新的版本.这就意味着库得去向后兼 ...
- 版本不兼容Jar包冲突该如何是好?
一.引言 "老婆"和"妈妈"同时掉进水里,先救谁? 常言道:编码五分钟,解冲突两小时.作为Java开发来说,第一眼见到ClassNotFoundExceptio ...
- eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错? java.lang.ClassNotFoundException: com.branchitech.app.startup.AppStartupContextListener java.lang.ClassN
eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错?java. ...
- 用命令行编译java并生成可执行的jar包
用命令行编译java并生成可执行的jar包 1.编写源代码. 编写源文件:CardLayoutDemo.java并保存,例如:I:\myApp\CardLayoutDemo.java.程序结构如下: ...
- java转换json需要导入的jar包,org/apache/commons/lang/exception/NestableRuntimeException
缺少相应jar包都会有异常,根据异常找jar包导入...... 这里我说下lang包,因为这个包我找了好半天: 我用的是: commons-lang3-3.1.jar 出现异常: jav ...
- 不要轻易在java ext 目录放任何三方jar包
今天在编写一个简单spi 应用demo的时候,在编译时总有一个其他的错误,如下: ERROR Failed to execute goal org.apache.maven.plugins:maven ...
- maven 本地仓库无法更新到最新版本的jar包
maven 本地仓库无法更新到最新版本的jar包 描述:maven 本地仓库无法更新最新版的jar包导致项目一直报错 解决:去jar包版本所在目录,删除掉所有红框内文件,重新用ide导入
- 转!java web项目 build path 导入jar包,tomcat启动报错 找不到该类
在eclipse集成tomcat开发java web项目时,引入的外部jar包,编译通过,但启动tomcat运行web时提示找不到jar包内的类,需要作如下配置,将jar包在部署到集成的tomcat环 ...
- Java SE Eclipse中引入第三方jar及class
使用eclipse开发Java SE 总免不了需要引入第三方的jar或者calss文件.这里给大家说一下如何在eclipse中引入第三方jar或者calss文件. 让我们先了解一下eclipse项目中 ...
随机推荐
- sklearn练习1 回归
from sklearn.svm import SVR from sklearn.pipeline import make_pipeline from sklearn.preprocessing im ...
- 2020.10.17【普及组】模拟赛C组 总结
总结 这次比赛 120 分,老师说上 200 是不容易的,但我觉得这不是我真的水平 改题情况 T1 题目大意:有 N 个小朋友,每个小朋友有 \(B_i\) 个朋友,问从中随机选 3 人使得 3 人关 ...
- XDEBUG 选项
到官网 http://www.xdebug.com/download.php 下载 找到对应PHP版本的 Xdebug ,后面带 TS 的为线程安全,本机环境为 win7 64 + php-5.5.1 ...
- 开发工具-在线生成GUID
更新记录 2022年6月11日 记录开始. https://www.toolbaba.cn/d/dev_guid http://tool.pfan.cn/guidgen https://www.iam ...
- Linux云服务器 磁盘分区失败
背景:阿里云服务器,df -h /dev/vda1有40g,然后想把这40g拆一下,拆成几个分区,挂载到不同的路径下. 行动:需要先卸载挂载的盘,但是umount失败,通过fuser删除盘上的服务失 ...
- Spring Security自定义认证器
在了解过Security的认证器后,如果想自定义登陆,只要实现AuthenticationProvider还有对应的Authentication就可以了 Authentication 首先要创建一个自 ...
- WPF开发随笔收录-ScrollViewer滑块太小解决方案
一.前言 在WPF开发过程中,ScrollViewer是一个很常使用到的控件,在自己工作的项目中,收到一个反馈就是当ScrollViewer里面的内容太长时,滚动条的滑块就会变得很小,然后导致点击起来 ...
- 7 个有趣的 Python 实战项目,超级适合练手
关于Python,有一句名言:不要重复造轮子. 但是问题有三个: 1.你不知道已经有哪些轮子已经造好了,哪个适合你用.有名有姓的的著名轮子就400多个,更别说没名没姓自己在制造中的轮子. 2.确实没重 ...
- easyexcel注解
1.@ExcelProperty 必要的一个注解,注解中有三个参数value,index分别代表列明,列序号 1.value 通过标题文本对应2.index 通过文本行号对应 2.@ColumnWit ...
- [零基础学IoT Pwn] 环境搭建
[零基础学IoT Pwn] 环境搭建 0x00 前言 这里指的零基础其实是我们在实战中遇到一些基础问题,再相应的去补充学习理论知识,这样起码不会枯燥. 本系列主要是利用网上已知的IoT设备(路由器)漏 ...