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
目錄,包名都建好,可以自定義,後續編譯指令自行調整即可。
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
代碼
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
本文來自部落格園,作者:Grey Zeng,轉載請注明原文連結:https://www.cnblogs.com/greyzeng/p/16587776.html