Java SE 9 多版本兼容 JAR 包示例
Java SE 9 多版本兼容 JAR 包示例
作者:Grey
说明
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
代码
参考资料
Multi-Release JAR Files with Maven
JEP 238: Multi-Release JAR Files
Java SE 9 多版本兼容 JAR 包示例的更多相关文章
- java9新特性-6-多版本兼容jar包
1.官方Feature 238: Multi-Release JAR Files 2.使用说明 当一个新版本的Java出现的时候,你的库用户要花费数年时间才会切换到这个新的版本.这就意味着库得去向后兼 ...
- 版本不兼容Jar包冲突该如何是好?
一.引言 "老婆"和"妈妈"同时掉进水里,先救谁? 常言道:编码五分钟,解冲突两小时.作为Java开发来说,第一眼见到ClassNotFoundExceptio ...
- 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. ...
- 用命令行编译java并生成可执行的jar包
用命令行编译java并生成可执行的jar包 1.编写源代码. 编写源文件:CardLayoutDemo.java并保存,例如:I:\myApp\CardLayoutDemo.java.程序结构如下: ...
- java转换json需要导入的jar包,org/apache/commons/lang/exception/NestableRuntimeException
缺少相应jar包都会有异常,根据异常找jar包导入...... 这里我说下lang包,因为这个包我找了好半天: 我用的是: commons-lang3-3.1.jar 出现异常: jav ...
- 不要轻易在java ext 目录放任何三方jar包
今天在编写一个简单spi 应用demo的时候,在编译时总有一个其他的错误,如下: ERROR Failed to execute goal org.apache.maven.plugins:maven ...
- maven 本地仓库无法更新到最新版本的jar包
maven 本地仓库无法更新到最新版本的jar包 描述:maven 本地仓库无法更新最新版的jar包导致项目一直报错 解决:去jar包版本所在目录,删除掉所有红框内文件,重新用ide导入
- 转!java web项目 build path 导入jar包,tomcat启动报错 找不到该类
在eclipse集成tomcat开发java web项目时,引入的外部jar包,编译通过,但启动tomcat运行web时提示找不到jar包内的类,需要作如下配置,将jar包在部署到集成的tomcat环 ...
- Java SE Eclipse中引入第三方jar及class
使用eclipse开发Java SE 总免不了需要引入第三方的jar或者calss文件.这里给大家说一下如何在eclipse中引入第三方jar或者calss文件. 让我们先了解一下eclipse项目中 ...
随机推荐
- VB.net使用Microsoft.Office.Interop.Excel对Excel进行简单的读取和写入
环境:Visual Stadio 2017 .NET Framework 4.6.1 1.直接进入正题,新建一个控制台程序,右键引用-管理Nuget程序包,搜索Microsoft.Office.In ...
- CF1682D Circular Spanning Tree
题意: 构造题,节点1~n顺时针排列成圆形,告诉你每个点度数奇偶性,让你构造一棵树,树边不相交. 思路: 因为每条边给总度数贡献2,因此如果度数为1的点有奇数个,直接输出no.显然0个度数为1的,也输 ...
- 历经70+场面试,我发现了大厂面试的bug,并总结其中心得
想起了学弟在去年秋招时面试了50余家,加上暑期实习面试了20余家,加起来也面试了70余场. 基本把国内有名的互联网公司都面了一遍,不敢说自己的面试经验很丰富,但也是不差的. 这次专门把大厂的面试做了个 ...
- 上线项目之局域网上线软件使用-----phpStudy
上面的图片是phpStudy的软件截图.那么你在哪里会下到呢?链接: https://pan.baidu.com/s/1lvX9jY_K6gGkMOqo76p4nA 提取码: h1it 复制这段内容后 ...
- jieba分词的功能和性能分析
jieba分词问题导引 用户词典大小最大可以有多大 用户词典大小对速度的影响 有相同前缀和后缀的词汇如何区分 对比百度分词的API 问题一:词典大小 从源码大小分析,整个jieba分词的源码总容量为8 ...
- 解决远程连接阿里云服务器的Redis失败问题
参考网址: https://www.pianshen.com/article/91461328818/ https://blog.csdn.net/weixin_42518709/article/de ...
- MySQL进行 批量插入,批量删除,批量更新,批量查询
1.批量插入 ServiceImpl层 List<Person> addPeople = new ArrayList<>(); //addPeople存放多个Person对象 ...
- HMS Core 机器学习服务打造同传翻译新“声”态,AI让国际交流更顺畅
2022年6月,HMS Core机器学习服务面向开发者提供一项全新的开放能力--同声传译,通过AI语音技术减少资源成本,加强沟通交流,旨在帮助开发者制作丰富多样的同声传译应用. HMS Core同声传 ...
- 抓到 Netty 一个隐藏很深的内存泄露 Bug | 详解 Recycler 对象池的精妙设计与实现
欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 最近在 Review Netty 代码的 ...
- windows版anaconda+CUDA9.0+cudnn7+pytorch+tensorflow安装
1.Anaconda 首先下载Anaconda,它是一个开源的python发行版本,含有众多科学工具包,直接安装anaconda免除了许多包的手动安装,点击这里下载. 按照你的实际情况选择下载.下载完 ...