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: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

代码

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

Java SE 9 多版本兼容 JAR 包示例的更多相关文章

  1. java9新特性-6-多版本兼容jar包

    1.官方Feature 238: Multi-Release JAR Files 2.使用说明 当一个新版本的Java出现的时候,你的库用户要花费数年时间才会切换到这个新的版本.这就意味着库得去向后兼 ...

  2. 版本不兼容Jar包冲突该如何是好?

    一.引言 "老婆"和"妈妈"同时掉进水里,先救谁? 常言道:编码五分钟,解冲突两小时.作为Java开发来说,第一眼见到ClassNotFoundExceptio ...

  3. eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错? java.lang.ClassNotFoundException: com.branchitech.app.startup.AppStartupContextListener java.lang.ClassN

    eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错?java. ...

  4. 用命令行编译java并生成可执行的jar包

    用命令行编译java并生成可执行的jar包 1.编写源代码. 编写源文件:CardLayoutDemo.java并保存,例如:I:\myApp\CardLayoutDemo.java.程序结构如下: ...

  5. java转换json需要导入的jar包,org/apache/commons/lang/exception/NestableRuntimeException

    缺少相应jar包都会有异常,根据异常找jar包导入......     这里我说下lang包,因为这个包我找了好半天:   我用的是: commons-lang3-3.1.jar  出现异常: jav ...

  6. 不要轻易在java ext 目录放任何三方jar包

    今天在编写一个简单spi 应用demo的时候,在编译时总有一个其他的错误,如下: ERROR Failed to execute goal org.apache.maven.plugins:maven ...

  7. maven 本地仓库无法更新到最新版本的jar包

    maven 本地仓库无法更新到最新版本的jar包 描述:maven 本地仓库无法更新最新版的jar包导致项目一直报错 解决:去jar包版本所在目录,删除掉所有红框内文件,重新用ide导入

  8. 转!java web项目 build path 导入jar包,tomcat启动报错 找不到该类

    在eclipse集成tomcat开发java web项目时,引入的外部jar包,编译通过,但启动tomcat运行web时提示找不到jar包内的类,需要作如下配置,将jar包在部署到集成的tomcat环 ...

  9. Java SE Eclipse中引入第三方jar及class

    使用eclipse开发Java SE 总免不了需要引入第三方的jar或者calss文件.这里给大家说一下如何在eclipse中引入第三方jar或者calss文件. 让我们先了解一下eclipse项目中 ...

随机推荐

  1. VB.net使用Microsoft.Office.Interop.Excel对Excel进行简单的读取和写入

    环境:Visual Stadio 2017  .NET Framework 4.6.1 1.直接进入正题,新建一个控制台程序,右键引用-管理Nuget程序包,搜索Microsoft.Office.In ...

  2. CF1682D Circular Spanning Tree

    题意: 构造题,节点1~n顺时针排列成圆形,告诉你每个点度数奇偶性,让你构造一棵树,树边不相交. 思路: 因为每条边给总度数贡献2,因此如果度数为1的点有奇数个,直接输出no.显然0个度数为1的,也输 ...

  3. 历经70+场面试,我发现了大厂面试的bug,并总结其中心得

    想起了学弟在去年秋招时面试了50余家,加上暑期实习面试了20余家,加起来也面试了70余场. 基本把国内有名的互联网公司都面了一遍,不敢说自己的面试经验很丰富,但也是不差的. 这次专门把大厂的面试做了个 ...

  4. 上线项目之局域网上线软件使用-----phpStudy

    上面的图片是phpStudy的软件截图.那么你在哪里会下到呢?链接: https://pan.baidu.com/s/1lvX9jY_K6gGkMOqo76p4nA 提取码: h1it 复制这段内容后 ...

  5. jieba分词的功能和性能分析

    jieba分词问题导引 用户词典大小最大可以有多大 用户词典大小对速度的影响 有相同前缀和后缀的词汇如何区分 对比百度分词的API 问题一:词典大小 从源码大小分析,整个jieba分词的源码总容量为8 ...

  6. 解决远程连接阿里云服务器的Redis失败问题

    参考网址: https://www.pianshen.com/article/91461328818/ https://blog.csdn.net/weixin_42518709/article/de ...

  7. MySQL进行 批量插入,批量删除,批量更新,批量查询

    1.批量插入 ServiceImpl层 List<Person> addPeople = new ArrayList<>(); //addPeople存放多个Person对象 ...

  8. HMS Core 机器学习服务打造同传翻译新“声”态,AI让国际交流更顺畅

    2022年6月,HMS Core机器学习服务面向开发者提供一项全新的开放能力--同声传译,通过AI语音技术减少资源成本,加强沟通交流,旨在帮助开发者制作丰富多样的同声传译应用. HMS Core同声传 ...

  9. 抓到 Netty 一个隐藏很深的内存泄露 Bug | 详解 Recycler 对象池的精妙设计与实现

    欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 最近在 Review Netty 代码的 ...

  10. windows版anaconda+CUDA9.0+cudnn7+pytorch+tensorflow安装

    1.Anaconda 首先下载Anaconda,它是一个开源的python发行版本,含有众多科学工具包,直接安装anaconda免除了许多包的手动安装,点击这里下载. 按照你的实际情况选择下载.下载完 ...