Java9系列第三篇-同一个Jar支持多JDK版本运行

我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注。期待您能关注我,我将把java 9 写成一系列的文章,大概十篇左右。
本文内容:在Java 9增强了JAR多版本字节码文件格式的支持,同一个Jar包可以包含多个Java版本的class文件。使用这个功能,我们可以将应用程序/库升级到新的Java版本,而不必强迫用户升级到相同的Java版本。
一、基本使用方法
多版本的字节码发行jar包,需要在其MANIFEST.MF中做以下的声明:
Multi-Release: true
在jar包的META-INF/versions文件目录里面可以包含多个版本的class文件,编译结果目录结构如下:
jar root
- A.class
- B.class
- META-INF
- versions
- 9
- A.class
假设上文中的根目录是使用java 8 或之前版本编译的字节码文件A.calss。META-INF/versions/9/ 是使用java 9 编写的java代码的编译结果A.class。
- 如果jar包是在JDK 8的运行时环境下运行,将使用根目录下面的class文件进行程序运行。
- 如果jar包是在JDK 9的运行时环境下运行,将使用
META-INF/versions/9/下面的class文件进行程序运行。
假设未来这个项目升级JDK 10,决定在A.java中使用Java 10的一些新特性,可以单独针对A.class进行语法升级,并将编译结果a.class放置在META-INF/versions/10/ 下面
jar root
- A.class
- B.class
- META-INF
- versions
- 9
- A.class
- 10
- A.class
现在,上面的jar包含了可以以三种Java版本运行的字节码文件,A.class兼容JDK 8、9、10。
二、真实的例子
java 8代码
下面的类文件代码我们让它运行在Java 8的环境下
package com.example;
public class IOUtil {
public static String convertToString(InputStream inputStream) throws IOException {
System.out.println("IOUtil 使用java 8 版本");
Scanner scanner = new Scanner(inputStream, "UTF-8");
String str = scanner.useDelimiter("\\A").next();
scanner.close();
return str;
}
}
增加一个Main.java的应用程序入口文件,调用IOUtil.convertToString方法将InputStream转换成String。
package com.example;
public class Main {
public static void main(String[] args) throws IOException {
InputStream inputStream = new ByteArrayInputStream("测试字符串".getBytes());
String result = IOUtil.convertToString(inputStream);
System.out.println(result);
}
}
Java 9代码
在Java 9 发布之后,我们决定使用Java 9 的新的语法重写IOUtil.convertToString方法。
package com.example;
public class IOUtil {
public static String convertToString(InputStream inputStream) throws IOException {
System.out.println("IOUtil 使用java 9 版本");
try (inputStream) { //Java9版本的增强try-with-resources
String str = new String(inputStream.readAllBytes());
return str;
}
}
}
如上的代码所示,我们使用了Java 9的两个新特性带有inputStream引用的try-with-resource块和新的InputStream.readAllBytes()方法。
编译
将Java8 、Java9的IOUtil.java代码分别在JDK8、JDK9的版本下分别编译成class字节码文件,并将class文件按照如下的目录结构打成保存,并打jar包。(先按java8版本打成jar包,然后修改MANIFEST.MF文件,添加java 9字节码class文件即可)
D:\multi-release-jar-example\my-lib-jar>tree /A /F
+---com
| \---example
| IOUtil.class
| Main.class
|
\---META-INF
| MANIFEST.MF
|
\---versions
\---9
\---com
\---example
IOUtil.class
运行 Main class
在JDK 9的环境下运行这个jar包
D:\multi-release-jar-example>java -cp my-lib.jar com.example.Main
IOUtil 使用java 9 版本
测试字符串
在JDK 8的环境下运行这个jar包
D:\multi-release-jar-example>C:\jdk1.8.0_151\bin\java -cp my-lib.jar com.example.Main
IOUtil 使用java 8 版本
测试字符串
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
Java9系列第三篇-同一个Jar支持多JDK版本运行的更多相关文章
- 深入理解javascript函数系列第三篇——属性和方法
× 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...
- 深入理解javascript函数系列第三篇
前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...
- javascript面向对象系列第三篇——实现继承的3种形式
× 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...
- 深入理解javascript作用域系列第三篇——声明提升(hoisting)
× 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...
- Webpack系列-第三篇流程杂记
系列文章 Webpack系列-第一篇基础杂记 Webpack系列-第二篇插件机制杂记 Webpack系列-第三篇流程杂记 前言 本文章个人理解, 只是为了理清webpack流程, 没有关注内部过多细节 ...
- 深入理解javascript作用域系列第三篇
前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hois ...
- 查看jar包的jdk版本并降级
用解压工具打开jar包(例子都是用7zip) 进入到META-INF目录,查看MANIFEST.MF文件,查看Bulid-Jdk,下图就为1.7.0_55版本的JDK,这就表示jetty-serv ...
- jar包、jdk版本、兼容性
对jar包.jdk版本,以及不同jdk版本的jar包的兼容性有一些疑问,搜集一些资料于此 查看jar包的jdk版本 查看.jar包中的META-INF\MANIFEST.MF Build-Jdk: 1 ...
- Java9系列第8篇-Module模块化编程
我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...
随机推荐
- pyhton:操作redis
一.redis介绍 redis是一种非关系型数据库:没有表结构,没有字段,没有sql语句.只是用get获取数据,set插数据,类似字典.比如mangodb,redis redis的数据全存在内存,re ...
- cmd运行SpringBoot的jar中文乱码
问题: 通过以下命令启动springBoot项目后,在项目中查看日志,发现中文乱码 java -jar projectName.jar 解决 启动时添加参数-Dfile.encoding=UTF-8即 ...
- 【原创】Kuberneters-HelmV3.3.1入门介绍及实践
一.为什么需要Helm? Kubernetes目前已成为容器编排的事实标准,随着传统架构向微服务容器化架构的转变,从一个巨大的单体的应用切分为多个微服务,每个微服务可独立部署和扩展,实现了敏捷开发和快 ...
- 《Redis内存数据库》Redis环境搭建
前言 Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多 ...
- NetCore微服务实战体系:日志管理
一. 起始 进入NetCore时代,日志的使用有了很大的变化,因为跨平台以及虚拟化技术的使用,日志不能够再像Framework的方式直接记录在文本,文本其实也可以,但是日志的管理以及查看都不太方便.L ...
- python判断链表是否有环
思路:使用快慢指针,快指针每次走两步,慢指针每次走一步,如果有环,则一定会快慢指针指向同一结点: 假设环的长度为n,先让一个指针走n步,另一个再开始走,当他们指针指向同一结点时,该结点就是环入口点 ( ...
- Docker公共&本地镜像仓库(七)
分发镜像 我们已经会构建自己的镜像了,那么如果在多个docker主机上使用镜像那?有如下的几种可用的方法: 用相同的Dockerfile在其他host上构建镜像 将镜像上传到公共registry(比如 ...
- hystrix源码小贴士之之hystrix-metrics-event-stream
hystrix-metrics-event-stream主要提供了一些servlet,可以让用户通过http请求获取metrics信息. HystrixSampleSseServlet 继承了Http ...
- ASP.NET Core 3.x启动时运行异步任务(二)
这一篇是接着前一篇在写的.如果没有看过前一篇文章,建议先去看一下前一篇,这儿是传送门 一.前言 前一篇文章,我们从应用启动时异步运行任务开始,说到了必要性,也说到了几种解决方法,及各自的优缺点.最 ...
- MyBatis学习(一)初识MyBatis
一.MyBatis简介 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名 ...