乐趣区

关于javascript: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: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
退出移动版