写点什么

还在因 JDK 兼容问题发不同 JAR 包做兼容?MRJAR 了解一下?

用户头像
Android架构
关注
发布于: 刚刚


Java 9 版本中增强了 Jar 包多版本字节码文件格式支持,也就是说在同一个 Jar 包中我们可以包含多个 Java 版本的 class 文件,这样就能做到 Jar 包升级到新的 Java 版本(新特性 API 使用)时不用强迫使用方为了使用新 Jar 包而升级自己的业务模块 Java 版本,也不用针对不同最低支持 Java 版本提供不同的 Jar,真正的做到了一个 Jar 包兼容所有的目的。这样的 Jar 称为 MRJAR。


MRJAR 中的代码包含在不同版本 JDK 下编译的 class 文件。譬如使用 JDK9 编译的类可以调用 JDK9 提供的 API,而使用 JDK8 编译的类可以调用 JDK8 提供的 API,只要保证他们在 MRJAR 中的包名、类名、类对外调用都一致即可。


MRJAR 规则




一般典型情况下的 JAR 包内部包含 class 文件和一个属性META-INF/MANIFEST.MF文件,如下:


  • jar-root

  • A.class

  • B.class

  • C.class

  • META-INF

  • MANIFEST.MF


MRJAR 扩展自 JAR 的目录结构,扩展了META-INF目录以便存储特定 JDK 版本的 class 文件,META-INF目录包含一个版本子目录,其中可能包含许多子目录,每个目录的命名需要与 JDK 主要版本相同。譬如,对特定于 JDK9 的 class 可以放在META-INF/versions/9目录下,对特定于 JDK10 的 class 可以放在META-INF/versions/10目录下等。所以一般典型情况下的 MRJAR 包内部大致如下:


  • jar-root

  • A.class

  • B.class

  • C.class

  • META-INF

  • MANIFEST.MF

  • versions

  • 9

  • A.class

  • D.class

  • 10

  • A.class

  • B.class


上面的例子中在不同 JDK 环境下运行表现如下:


  • 如果这个 MRJAR 在不支持 MRJAR 的 JDK 环境(譬如 JDK8)下使用,则会被自动兼容当做普通 JAR 使用,即META-INF/versions/目录下都被忽略,直接使用了 root 下的 class,所以无法访问 D。

  • 如果这个 MRJAR 在 JDK9 中使用,则只有 A、B、C、D 这几个 class 可以使用,且这里的 A、D 用的是META-INF/versions/9/下面的 class,其他用的 root 目录下的 class。

  • 对于 JDK10 来说,原理类同上面 JDK9,这里不多解释。只是说当我们在 JDK10 环境使用 C 类时搜索的顺序是先搜索META-INF/versions/10/下是否存在 C,如果不存在则搜索`META-INF/versions


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


/9/`下是否存在 C,如果不存在则搜索根 root 目录下是否存在,这个查找顺序一定要明白。


  • 对 JDK11 来说,因为不存在META-INF/versions/11/,所以依次在低于自己的版本中搜索,在这里也就等同于在 JDK10 下被命中的类。


制作 MRJAR




JDK9 对生成 JAR 包的各种命令和工具都升级为支持 MRJAR,所以制作 MRJAR 最好直接使用 JDK9 开始的环境,其 jar 命令新增了一个参数为--release,语法如下:


//N 代表一个 JDK 主版本,如 JDK9 中的 9,且 N 值必须大于等于 9;


//所有在--release N 之后的文件都会被添加到 MRJAR 的 META-INF/versions/N 目录下;


jar <options> --release N <other-options>


假设现在我们准备好了一套 JDK8 的类和一套 JDK12 的类和编译成 class 的产物,如下:


//JDK8 的源文件,编译产物目录假设为 jdk8/build/classes/


package cn.yan.mrjar;


public class JarUtil {


public String func() {


//JDK8 API 实现功能


}


}


//JDK12 的源文件,编译产物目录假设为 jdk12/build/classes/


package cn.yan.mrjar;


public class JarUtil {


public String func() {


//JDK12 API 实现功能


}


}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
还在因 JDK 兼容问题发不同 JAR 包做兼容?MRJAR 了解一下?