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:[email protected]">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:[email protected]">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:[email protected]">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
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/280675.html