做一个终身学习的人。

在这章节中, 主要介绍以下内容:

  • 封装Java模块的不同格式

  • JAR格式增强

  • 什么是多版本JAR

  • 如何创建和使用多版本JAR

  • JMOD是什么格式

  • 如何使用jmod工具来处理JMOD文件

  • 如何创建、解压和描述JMOD文件

  • 如何列出JMOD文件的内容

  • 如何在JMOD文件中记录模块的哈希值以进行依赖性验证

模块可以以不同的格式打包,以便在编译时,链接时和运行时三个阶段中使用。 但并不是在所有阶段都支持这四种格式。 JDK 9支持以下格式打包模块:

  • 展开的目录

  • JAR格式

  • JMOD格式

  • JIMAGE格式

在JDK 9之前支持展开的目录和JAR格式。JDK 9中的JAR格式已得到增强,以支持模块化JAR和多版本JAR。 JDK 9为封装模块引入了两种新格式:JMOD格式和JIMAGE格式。 本节主要讨论JAR格式和JMOD格式的增强。

一. JAR格式

在前面的第三者介绍了如何在jar工具中使用新的选项来创建模块化的JAR。 jar工具还用于列出JAR文件中的条目,并提取和更新JAR文件的内容。 该jar工具在JDK 9之前已经支持这些操作,并且在JDK 9中没有任何新的操作。在本章中,将介绍添加到JAR格式的新功能,称为多版本JAR。

1. 什么是多版本JAR

作为一名经验丰富的Java开发人员,你必须使用Java类库/框架,例如Spring框架,Hibernate等。您可能正在使用Java 8,但这些类库可能仍然在Java 6或Java 7中使用。为什么类库开发人员不能使用最新版的JDK来使用新功能? 其中一个原因是不是所有的类库使用者都使用最新的JDK。 更新类库以使用较新版本的JDK意味着强制所有类库用户迁移到较新的JDK,这在实践中是不可能的。 维护和发布针对不同JDK的类库是打包代码时的另一个痛苦。 通常,你将会找到一个用于不同JDK的单独的库JAR。 JDK 9通过为类库开发人员提供一种打包类库代码的新方法来解决这个问题,使用单个JAR包含多个JDK的类库的相同版本。 这样的JAR被称为多版本JAR。

多版本JAR(MRJAR)包含与多个JDK版本相同版本的类库(提供相同的API)。 也就是说,可以将类库作为可用于JDK 8和JDK 9的MRJAR。MRJAR中的代码将包含在JDK 8和JDK 9中编译的类文件。使用JDK 9编译的类可以利用JDK 9提供的API,而使用JDK 8编译的类可以提供使用JDK 8编写的相同的类库API。

MRJAR扩展了JAR的已有的目录结构。 JAR包含其所有内容所在的根目录。 它包含一个META-INF目录,用于存储有关JAR的元数据。 通常,JAR包含包含其属性的META-INF/MANIFEST.MF文件。 典型的JAR中的条目如下所示:

- jar-root
  - C1.class
  - C2.class
  - C3.class
  - C4.class- META-INF
  - MANIFEST.MF

JAR包含四个class文件和一个MANIFEST.MF文件。 MRJAR扩展了META-INF目录以存储特定于JDK版本的类。 META-INF目录包含一个版本子目录,其中可能包含许多子目录,每个目录命名与JDK主要版本相同。 例如,对于特定于JDK 9的类,可能有META-INF/versions/9目录,对于JDK 10特定的类,可能有一个名为META-INF/versions/10的目录等。典型的MRJAR 可能有以下条目:

- jar-root
  - C1.class
  - C2.class
  - C3.class
  - C4.class- META-INF
  - MANIFEST.MF
  - versions
    - 9      - C2.class
      - C5.class
    - 10      - C1.class
      - C2.class
      - C6.class

如果该MRJAR在不支持MRJAR的环境中使用,则将被视为常规JAR ——根目录中的内容将被使用,META-INF/version/9和 META-INF/versions/10目录下的类将被忽略。 因此,如果这个MRJAR与JDK 8一起使用,则只能使用四个类:C1,C2,C3和C4。

当在JDK 9中使用这个MRJAR时,有五个类可以执行:C1,C2,C3,C4和C5。 将使用META-INF/versions/9目录中的C2类,而不是根目录中的C2类。 在这种情况下,MRJAR表示它具有JDK 9的C2类的较新版本,该版本覆盖了JDK 8或更早版本的根目录中的C2版本。 JDK 9版本还添加了一个名为C5的新类。

同样,如果使用JDK 10,MRJAR会覆盖类C1和C2类,并且包含JDK版本10的名为C6的新类。

在单个MRJAR中定位多个JDK版本,MRJAR中的搜索过程与常规JAR不同。 在MRJAR中搜索资源或类文件使用以下规则:

  • JDK的主版本是针对使用MRJAR的环境决定的。 这里假设JDK的主版本是N。

  • 要查找名为R的资源或类文件,从版本N的目录搜索META-INF/versions目录下的特定平台的子目录。

  • 如果在子目录N中找到R,则返回。 否则搜索低于版本N的子目录。 对于META-INF/versions目录下的所有子目录,此过程将继续。

  • 当在META-INF/versions/N子目录中找不到R时,将搜索MRJAR的根目录。

我们来看一下使用以前显示的MRJAR结构的例子。 假设程序正在寻找C3.class,当前版本的JDK是10,搜索将从META-INF/versions/10开始,其中找不到C3.class。 在META-INF/versions/9中继续搜索,其中找不到C3.class。 现在搜索继续在根目录中,最后找到C3.class。

另一个例子,假设你想在JDK版本为10时找到C2.class。搜索从META-INF/versions/10开始,其中找到并返回C2.class。

另一个例子,假设你想在JDK版本为9时找到C2.class。搜索从META-INF/versions/9开始,其中找到并返回C2.class。

另一个例子,假设你想在JDK版本为8时找到C2.class。没有名为META-INF/versions/8的JDK 8特定目录。 因此,搜索从根目录开始,找到并返回C2.class。

Tips
在JDK 9中,处理JAR的所有工具(如java,javac和javap)都被修改为使用多版本的JAR。 处理JAR的API也已经更新,以处理多版本的JAR。

2. 创建多版本JAR

当在特定的JDK版本中搜索资源或类文件后,我们已经知道MRJAR中目录的搜索顺序,很容易了解如何找到类和资源。 有关JDK版本特定目录内容的一些规则。 将在后面的章节中描述这些规则。 在本节中,将重点介绍创建MRJAR。

要运行此示例,需要在计算机上安装JDK 8和JDK 9。 如果没有JDK 8,除JDK 9之外的任何其他JDK都可以。 对于除版本8以外的JDK,将需要更改示例中的代码,因此代码将使用你本地版本的JDK进行编译。

使用MRJAR来存储应用程序的JDK 8和JDK 9版本。 该应用程序由以下两个类组成:

com.jdojo.mrjar.Maincom.jdojo.mrjar.TimeUtil

Main类创建一个TimeUtil类的对象,并调用它的一个方法。Main类可以用作运行应用程序的主类。 TimeUtil类包含一个getLocalDate(Instant now)方法,它将Instant作为参数,并返回一个LocalDate类来表示当前时区的时间。 JDK 9已经为LocalDate类添加了一个新方法,它被命名为ofInstant(Instant instant, ZoneId zone)。 我们将更新应用程序以使用JDK 9并利用这种新方法,并保留使用JDK 8 中实现相同功能的Time API的旧应用程序。

源代码包含两个名为com.jdojo.mrjar.jdk8com.jdojo.mrjar.jdk9的NetBeans项目,它们分别配置为使用JDK 8和JDK 9。 在NetBeans中,需要将com.jdojo.mrjar.jdk8项目的源和库属性更改为JDK 8,并将 com.jdojo.mrjar.jdk9项目更改为JDK 9。这些项目的源代码很简单。 可以在TimeUtil类中创建一个静态方法的getLocalDate()方法。 在这里作为一个实例方法,所以你可以看到在输出(稍后讨论)哪个版本的实例化。 运行Main类时,会打印当前的本地日期,当你运行此示例时结果可能会有所不同。

下面包含使用JDK 8的TimeUtilMain类的代码。

// TimeUtil.javapackage com.jdojo.mrjar;import java.time.Instant;import java.time.LocalDate;import java.time.ZoneId;public class TimeUtil {    public TimeUtil() {        System.out.println("Creating JDK 8 version of TimeUtil...");
    }    public LocalDate getLocalDate(Instant now) {        return now.atZone(ZoneId.systemDefault())
                  .toLocalDate();
    }
}
// Main.javapackage com.jdojo.mrjar;import java.time.Instant;import java.time.LocalDate;public class Main {    public static void main(String[] args) {        System.out.println("Inside JDK 8 version of Main.main()...");        TimeUtil t = new TimeUtil();        LocalDate ld = t.getLocalDate(Instant.now());        System.out.println("Local Date: " + ld);
    }
}

下面包含使用JDK 9的TimeUtilMain类的代码模块声明为com.jdojo.mrjar。

// module-info.javamodule com.jdojo.mrjar {
    exports com.jdojo.mrjar;
}
// TimeUtil.javapackage com.jdojo.mrjar;import java.time.Instant;import java.time.LocalDate;import java.time.ZoneId;public class TimeUtil {    public TimeUtil() {        System.out.println("Creating JDK 9 version of TimeUtil...");
    }    public LocalDate getLocalDate(Instant now) {        return LocalDate.ofInstant(now, ZoneId.systemDefault());
    }
}
// Main.javapackage com.jdojo.mrjar;import java.time.Instant;import java.time.LocalDate;public class Main {    public static void main(String[] args) {        System.out.println("Inside JDK 9 version of Main.main()...");        TimeUtil t = new TimeUtil();        LocalDate ld = t.getLocalDate(Instant.now());        System.out.println("Local Date: " + ld);
    }
}

这个例子的目的不是单独运行这两个类,而是将它们全部包装在MRJAR中并运行它们。

JDK 9中的jar工具已得到增强,以支持创建MRJAR。 在JDK 9中,jar工具接受一个新的选项,叫做--release。 其语法如下:

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

这里,N是一个JDK主版本,如JDK 9中的9。N的值必须大于或等于9。所有在--release N选项之后的所有文件将被添加到 MRJAR的META-INF/versions/N目录下。

以下命令创建名为com.jdojo.mrjar.jar的MRJAR,并将其放在C:\ Java9Revealed\mrjars目录下,该目录是已经存在的目录:

C:\Java9Revealed>jar --create --file mrjars\com.jdojo.mrjar.jar-C com.jdojo.mrjar.jdk8\build\classes .--release 9 -C com.jdojo.mrjar.jdk9\build\classes .

请注意在此命令中使用--release 9选项。 来自com.jdojo.mrjar.jdk9\ build\classes目录的所有文件将被添加到MRJAR中的META-INF/versions/9目录中。 来自com.jdojo.mrjar.jdk8\build\classes目录的所有文件将被添加到MRJAR的根目录下。 MRJAR中的条目将如下所示:

- jar-root
  - com
    - jdojo
      - mrjar
        - Main.class
        - TimeUtil.class- META-INF
  - MANIFEST.MF
  - versions
    - 9
      - module-info.class
      - com
        - jdojo
          - mrjar
            - Main.class
            - TimeUtil.class

在创建MRJAR时,使用--verbose选项在jar工具中非常有帮助。 该选项打印出许多有用的信息,帮助诊断错误。 以下是与以前相同的命令,但使用了--verbose选项。 输出显示哪些文件被复制以及它们的位置:

C:\Java9Revealed>jar --create --verbose --file mrjars\com.jdojo.mrjar.jar-C com.jdojo.mrjar.jdk8\build\classes .--release 9 -C com.jdojo.mrjar.jdk9\build\classes .

输出信息为:

added manifest
added module-info: META-INF/versions/9/module-info.classadding: com/(in = 0) (out= 0)(stored 0%)adding: com/jdojo/(in = 0) (out= 0)(stored 0%)adding: com/jdojo/mrjar/(in = 0) (out= 0)(stored 0%)adding: com/jdojo/mrjar/Main.class(in = 1100) (out= 592)(deflated 46%)adding: com/jdojo/mrjar/TimeUtil.class(in = 884) (out= 503)(deflated 43%)adding: META-INF/versions/9/(in = 0) (out= 0)(stored 0%)adding: META-INF/versions/9/.netbeans_automatic_build(in = 0) (out= 0)(stored 0%)adding: META-INF/versions/9/.netbeans_update_resources(in = 0) (out= 0)(stored 0%)adding: META-INF/versions/9/com/(in = 0) (out= 0)(stored 0%)adding: META-INF/versions/9/com/jdojo/(in = 0) (out= 0)(stored 0%)adding: META-INF/versions/9/com/jdojo/mrjar/(in = 0) (out= 0)(stored 0%)adding: META-INF/versions/9/com/jdojo/mrjar/Main.class(in = 1328) (out= 689)(deflated 48%)adding: META-INF/versions/9/com/jdojo/mrjar/TimeUtil.class(in = 814) (out= 470)(deflated 42%)

假设要为MRJAR创建JDK的版本8,9和10。com.jdojo.mrjar.jdk10\build\classes目录包含特定于JDK 10的类,则以下命令将执行该任务:

C:\Java9Revealed>jar --create --file mrjars\com.jdojo.mrjar.jar-C com.jdojo.mrjar.jdk8\build\classes .--release 9 -C com.jdojo.mrjar.jdk9\build\classes .--release 10 -C com.jdojo.mrjar.jdk10\build\classes .

可以使用--list选项验证MRJAR中的条目,如下所示:

C:\Java9Revealed>jar --list --file mrjars\com.jdojo.mrjar.jar

输出结果为:

META-INF/
META-INF/MANIFEST.MF
com/
com/jdojo/com/jdojo/mrjar/
com/jdojo/mrjar/Main.classcom/jdojo/mrjar/TimeUtil.classMETA-INF/versions/9/
META-INF/versions/9/com/META-INF/versions/9/com/jdojo/
META-INF/versions/9/com/jdojo/mrjar/META-INF/versions/9/com/jdojo/mrjar/Main.classMETA-INF/versions/9/com/jdojo/mrjar/TimeUtil.classMETA-INF/versions/9/module-info.classMETA-INF/versions/10/
META-INF/versions/10/com/META-INF/versions/10/com/jdojo/
META-INF/versions/10/com/jdojo/mrjar/META-INF/versions/10/com/jdojo/mrjar/TimeUtil.class

假设有一个包含JDK 8的资源和类文件的JAR,并且希望通过为JDK 9添加资源和类文件来更新JAR以使其成为MRJAR。可以通过使用以下命令来更新JAR的内容: --update。 以下命令创建仅具有JDK 8文件的JAR:

C:\Java9Revealed>jar --create --file mrjars\com.jdojo.mrjar.jar-C com.jdojo.mrjar.jdk8\build\classes .

以下命令更新JAR以使其成为MRJAR:

C:\Java9Revealed>jar --update --file mrjars\com.jdojo.mrjar.jar--release 9 -C com.jdojo.mrjar.jdk9\build\classes .

看看这个MRJAR的运作。 以下命令运行com.jdojo.mrjar包中的Main类,将MRJAR放在类路径上。 JDK 8用于运行类。

C:\Java9Revealed> c:\java8\bin\java -classpath mrjars\com.jdojo.mrjar.jar com.jdojo.mrjar.Main

输出结果为:

Inside JDK 8 version of Main.main()...
Creating JDK 8 version of TimeUtil...
Local Date: 2017-06-27

输出显示,从MRJAR的根目录使用了两个类MainTimeUtil类,因为JDK 8不支持MRJAR。 以下命令使用模块路径运行相同的类。 在JDK 9中用于运行命令:

C:\Java9Revealed> c:\java9\bin\java --module-path mrjars\com.jdojo.mrjar.jar --module com.jdojo.mrjar/com.jdojo.mrjar.Main

输出结果为:

Inside JDK 9 version of Main.main()...
Creating JDK 9 version of TimeUtil...
Local Date: 2017-06-27

输出显示,从MRJAR的META-INF/versions/9目录中使用了两个类MainTimeUtil,因为JDK 9支持MRJAR,MRJAR具有JDK 9特有的这些类的版本。

让我们给这个MRJAR一点点变化。 创建具有相同内容的MRJAR,但在META-INF/versions/9目录中没有Main.class文件。 在现实世界的场景中,只有TimeUtil类在应用程序的JDK 9版本中发生变化,因此不需要为JDK 9打包Main类。JDK 8的Main类也可用于JDK 9。 以下命令打包我们上次执行的所有操作,除了JDK 9的Main类之外。生成的MRJAR命名为com.jdojo.mrjar2.jar。

C:\Java9Revealed>jar --create --verbose --file mrjars\com.jdojo.mrjar2.jar-C com.jdojo.mrjar.jdk8\build\classes .--release 9-C com.jdojo.mrjar.jdk9\build\classes module-info.class-C com.jdojo.mrjar.jdk9\build\classes com\jdojo\mrjar\TimeUtil.class

可以使用以下命令验证新MRJAR的内容:

C:\Java9Revealed>jar --list --file mrjars\com.jdojo.mrjar2.jar

输出的结果为:

http://www.cnblogs.com/IcanFixIt/p/7095839.html

延伸阅读

向着Java前进-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训向着Java前进