什么是 MANIFEST 文件?

JAR 文件支持广泛的功能,包括电子签名、版本控制、包封装等等。什么赋予 JAR 文件这种多样性?答案是 JAR 文件的 MANIFEST 文件。

MANIFEST 是一个特殊的文件,可以包含有关打包在 JAR 文件中的文件的信息。通过调整 MANIFEST 包含的这些“元”信息,您可以使 JAR 文件具有各种用途。

本课程将解释 MANIFEST 文件的内容,并向您展示如何处理它,包括以下基本功能的示例:

1.了解默认 MANIFEST
2.修改 MANIFEST 文件
3.设置应用程序的入口点
4.将类添加到 JAR 文件的类路径中
5.设置包版本信息
6.在 JAR 文件中封装包
7.利用 MANIFEST 属性增强安全性

1.理解默认 MANIFEST

当您创建 JAR 文件时,它自动获得一个默认的 MANIFEST 文件。一个存档中只能有一个 MANIFEST 文件,并且它的路径名总是 META-INF/MANIFEST.MF。

当您创建一个 JAR 文件时,默认的 MANIFEST 文件只包含以下内容:

Manifest-Version: 1.0
Created-By: 1.7.0_06 (Oracle Corporation)
这些行显示 MANIFEST 条目采用“头: 值”对的形式。头的名称与其值以冒号分隔。默认的 MANIFEST 符合 MANIFEST 的 1.0 版本规范,并由 JDK 的 1.7.0_06 版本创建。

MANIFEST 还可以包含有关打包在存档中的其他文件的信息。记录在 MANIFEST 中的关于其他文件的信息应该取决于您打算如何使用 JAR 文件。默认的 MANIFEST 不会对其他文件的信息记录做出任何假设。

默认 MANIFEST 中不包含数字签名信息。要了解有关数字签名和验证的详细信息,请参见签名和验证 JAR 文件教程。

2.修改清单文件

您可以使用m命令行选项在创建JAR文件时添加自定义信息到清单中。本节介绍了m选项。

Jar工具会自动将一个默认清单文件META-INF/MANIFEST.MF放入任何您创建的JAR文件中。您可以通过修改默认清单来启用特殊的JAR文件功能,如包封存。一般来说,修改默认清单包括向清单添加特殊目的头文件,以允许JAR文件执行特定的期望功能。

为了修改清单,您首先需要准备一个文本文件,其中包含您想添加到清单的信息。然后,您使用Jar工具的m选项将文件中的信息添加到清单中。

警告:从文本文件中创建清单的文本文件必须以新行或回车符结束。如果最后一行不以新行或回车符结束,则最后一行将无法正确解析。

基本命令格式如下:

jar cfm jar-file manifest-addition input-file(s) 让我们来看一下此命令中使用的选项和参数:

  • c选项表示您要创建JAR文件。
  • m选项表示您要合并一个现有文件中的信息到您正在创建的JAR文件的清单文件中。
  • f选项表示您想要输出到一个文件(您正在创建的JAR文件)而不是标准输出。
  • manifest-addition是现有文本文件的名称(或路径和名称),您希望将其内容添加到JAR文件清单的内容中。
  • jar-file是您希望生成的JAR文件的名称。
  • input-file(s)参数是一个由一个或多个文件的空格分隔的列表,您希望将这些文件放在您的JAR文件中。

-m和-f选项必须与相应的参数以相同的顺序排列。

3.设置应用的入口

如果您将应用程序打包成JAR文件,您需要某种方式来说明JAR文件中的哪个类是您的应用程序入口点。您可以使用清单文件中的Main-Class头来提供这些信息,具体格式为:

Main-Class: classname

其中,classname是您的应用程序入口点类的名称。

请注意,入口点是具有以下签名的方法的类:public static void main(String [] args)。

在设置了清单中的Main-Class头之后,您可以使用以下形式的java命令来运行JAR文件:

java -jar JAR-name

将执行在Main-Class头中指定的类的main方法。

接下来,以一个例子来说明:
当我们运行JAR文件时,我们想要在名称为MyPackage的包中的MyClass类中执行main方法。
首先,我们创建一个名为Manifest.txt的文本文件,具有以下内容:

Main-Class: MyPackage.MyClass

警告:确保文本文件以换行符或回车符结尾,如果不以换行符或回车符结尾,最后一行将无法正确解析。

然后,我们输入以下命令来创建一个名为MyJar.jar的JAR文件:

jar cfm MyJar.jar Manifest.txt MyPackage/*.class

这将创建一个具有以下内容的清单的JAR文件:

Manifest-Version: 1.0
Created-By: 1.7.0_06 (Oracle Corporation)
Main-Class: MyPackage.MyClass

当使用以下命令运行JAR文件时,MyClass类的主方法将被执行:

java -jar MyJar.jar

"e"标志用于在不显式编辑的情况下设置清单文件中的入口点。它通常用于创建或更新JAR文件。我们可以使用以下命令来创建具有入口点的JAR文件:

jar cfe app.jar MyApp MyApp.class

该命令将创建一个名为app.jar的JAR文件,其中清单中的Main-Class属性设置为MyApp。我们可以使用以下命令运行该应用程序:

java -jar app.jar

如果入口点类位于包中,我们可以使用包名和类名之间的点号来指定它,例如:

jar cfe Main.jar foo.Main foo/Main.class

4.向JAR文件的类路径中添加类

您可能需要从JAR文件内部引用其他JAR文件中的类。

例如,在典型情况下,小程序打包在一个JAR文件中,该文件的清单引用不同的JAR文件(或多个不同的JAR文件),以便将其用作小程序的实用工具。

您可以在小程序或应用程序的清单文件中的Class-Path header字段中指定要包含的类。Class-Path头采用以下形式:

Class-Path: jar1-name jar2-name directory-name/jar3-name

通过在manifest.yml中使用Class-Path header,您可以避免在调用Java来运行应用程序时指定较长的-classpath标志。

注意:Class-Path标头指向本地网络上的类或JAR文件,而不是JAR文件内部或通过Internet协议可访问的类。要将JAR文件中的类加载到类路径中,您必须编写自定义代码以加载这些类。例如,如果MyJar.jar包含名为MyUtils.jar的另一个JAR文件,则不能在MyJar.jar的清单中使用Class-Path头来将MyUtils.jar中的类加载到类路径中。

这是一个例子,我们想要将MyUtils.jar中的类加载到MyJar.jar中的类路径中。这两个JAR文件在同一个目录中。

首先,我们创建一个名为Manifest.txt的文本文件,其内容如下:

Class-Path:MyUtils.jar

警告:文本文件必须以新行或回车符结束。如果不以新行或回车符结束,则最后一行无法正确解析。

然后输入以下命令,创建一个名为MyJar.jar的JAR文件:

jar cfm MyJar.jar Manifest.txt MyPackage/*.class 这会创建带有以下内容的清单(Manifest)的JAR文件:

Manifest-Version: 1.0
Class-Path: MyUtils.jar
Created-By: 1.7.0_06 (Oracle Corporation)

当您运行MyJar.jar时,MyUtils.jar中的类现在已加载到类路径中。