首页 > 编程语言 >Java SE 9 多版本兼容 JAR 包示例

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

时间:2022-08-15 11:59:31浏览次数:87  
标签:git java jdk 示例 jar JAR 版本 Java hello

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

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

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

标签:git,java,jdk,示例,jar,JAR,版本,Java,hello
From: https://www.cnblogs.com/greyzeng/p/16587776.html

相关文章

  • Java NIO全面详解(看这篇就够了)
    很多技术框架都使用NIO技术,学习和掌握JavaNIO技术对于高性能、高并发网络的应用是非常关键的@mikechenNIO简介NIO中的N可以理解为Non-blocking,不单纯是New,是解决......
  • 【java面试题】ArrayList和LinkedList的区别
    【java面试题】ArrayList和LinkedList的区别 ArrayList和LinkedList都实现了List接口,它们有一下的不同点:ArrayList是基于索引的数据接口,它的底层是数组,它可以以O(1)时......
  • JavaScript 异步函数的 Promisification 处理
    Promisification是一个很长的词,表示一个编程范式的转变,即将接受回调的函数转换为一个返回类型为Promise的函数。我们现实的开发项目中经常需要这种转换,因为许多函数和......
  • Java 9.回文数
    给你一个整数x,如果x是一个回文整数,返回true;否则,返回false。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。   例如,121是回文,而123不是。来源:力扣......
  • 一文讲透Java核心技术之高可扩展利器SPI
    大家好,我是冰河~~SPI的概念JAVASPI=基于接口的编程+策略模式+配置文件的动态加载机制SPI的使用场景Java是一种面向对象语言,虽然Java8开始支持函数式编程和Stream,但是......
  • JAVA 发布订阅模式
    JAVA发布订阅模式一、发布订阅模式在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为......
  • 【java面试题】面向对象的特征
    【java面试题】面向对象的特征 面向对象编程是利用类和对象编程的一种思想,万物可归类,类是对于世界事物的高度抽象,万物皆对象,对象是具体的世界事物。面向对象的三大特征......
  • 长篇图解java反射机制及其应用场景
    一、什么是java反射?在java的面向对象编程过程中,通常我们需要先知道一个Class类,然后new类名()方式来获取该类的对象。也就是说我们需要在写代码的时候(编译期或者编译期之......
  • Java开发学习(二十五)----使用PostMan完成不同类型参数传递
    一、请求参数请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数?关于请求参数的......
  • 【Java】List排序方法(包括对象、Map等内部排序实现)
    前言日常开发中经常会对List集合做排序操作,JDK为我们提供了强大的排序方法,可以针对对象、Map、基本类型等进行正/倒排序操作。参考博客:JAVA列表排序方法sort和reversed......