Java SE 9 多版本兼容 JAR 包示例

Java SE 9 多版本兼容 JAR 包示例

作者:Grey

原文地址:Java SE 9 多版本兼容 JAR 包示例

说明

Java 9 版本中增强了Jar 包多版本字节码文件格式支持,也就是说在同一个 Jar 包中我们可以包含多个 Java 版本的 class 文件,这样就能做到 Jar 包升级到新的 Java 版本时不用强迫使用方为了使用新 Jar 包而升级自己的业务模块 Java 版本,也不用针对不同最低支持 Java 版本提供不同的 Jar,真正的做到了一个 Jar 包兼容所有的目的。

本文通过以下示例来说明多版本 Jar 包的使用。

环境准备

机器上应该有多个版本的 JDK 用于测试,并且至少有一个是 JDK 9 或者更高版本。

命令行编译示例

注:本示例无需使用 IDE ,我们用最原始的方式创建一个多版本的 Jar 包。

新建一个文件夹,用项目名称命名,并且在其中把src目录,包名都建好,可以自定义,后续编译命令自行调整即可。

image

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");     } } 

创建好上述类以后,项目结构如下

image

接下来是编译,在项目目录下,用 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 项目,结构如下

image

和上例类似,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 

代码

hello-mrjar

hello-mrjar-with-maven

参考资料

Multi-Release JAR Files with Maven

Java 9 多版本兼容 jar 包

Multi-Release Jar Files

JEP 238: Multi-Release JAR Files

商匡云商
Logo
注册新帐户
对比商品
  • 合计 (0)
对比
0
购物车