本文翻译:https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#Notes_on_Manifest_and_Signature_Files
笔者水平有限,如有描述不准确的地方,还请批评指正。
一、介绍
JAR文件是基于ZIP文件格式的一种文件格式,用来将许多文件整合成一个文件。一个JAR文件本质上是包含可选目录META-INF的zip文件,可以通过命令行jar工具或者在Java平台上使用java.util.jar中的API来创建。JAR文件的命名没有严格的要求,可以是特定平台上的任意合法文件名称。
在很多场景中,JAR文件不仅仅用来对java class文件和资源文件进行归档,还被用来作应用程序及其扩展的构建块。如果包含META-INF目录,则是用来存储包信息和扩展配置数据,配置数据包括安全信息,版本控制信息,扩展信息和服务信息等。
二、META-INF目录
在Java 2平台会识别和解释META-INF目录下面的文件和目录,以配置应用程序、扩展、类加载器和服务。
MANIFEST.MF是用来定义扩展和包相关数据的清单文件。
INDEX.LIST通过jar工具的-i选项来生成,它包含应用程序及其扩展程序中的包的位置信息,同时它是JarIndex实现的一部分,类加载器使用它来提高类的加载速度。
x.SF是JAR文件的签名文件,x表示基本文件名称。
x.DSA是于x.SF关联的签名块文件,它们有相同的基本文件名。此文件存储相应签名文件的数字签名。
services/ 该目录存储所有服务提供程序配置文件。
三、名称-值对和节
在我们深入每个配置文件的细节之前,需要定义一些格式约定。
在大部分场景中,包含在清单文件和签名文件中的信息表示为受RFC822标准启发的所谓的“名称:值”对。“名称:值”对也被称为头和属性。名称-值对组称为“节”,每一“节”通过空行分离。
任何形式的二进制数据都表示为base64。行的长度超过72字节的二进制数据需要延续。摘要和签名就是二进制数据的例子。
实现应该最多支持65535字节的头值。
本文档中的所有规范使用相同的语法,其中终端符号以固定宽度字体显示,非终端符号以斜体字体显示。
节规范:
section: *header +newline
nonempty-section: +header +newline
newline: CR LF | LF | CR (not followed by LF)
header: name : value
name: alphanum *headerchar
value: SPACE *otherchar newline *continuation
continuation: SPACE *otherchar newline
alphanum: {A-Z} | {a-z} | {0-9}
headerchar: alphanum | - | _
otherchar: any UTF-8 character except NUL, CR and LF
; Also: To prevent mangling of files sent via straight e-mail, no
; header will start with the four letters "From".
上述规范中定义的非终端符号将在以下规范中引用。
四、JAR Manifest
1. 概述
JAR文件的清单由主节和拥有多个私有JAR文件条目的单独节列表,每行通过换行符分隔。主节和单独节都遵循上面指定的节语法。它们都有自己特定的限制和规则。
主节包括包括JAR文件自身的安全和配置信息,以及此JAR文件所属应用程序及扩展。清单文件同样定义了每个单独清单条目的主属性。每节中没有属性可以使用“Name”作为名称。每一节通过空行结束。
单独节定义了JAR文件中包和文件的各种属性。不是所有在JAR文件中的文件都需要被作为条目列在清单中,但是所有被签名的文件必须被列出。清单文件自身不需要被列出。每节必须以名称“Name”的属性作为开始,并且值必须是该文件的的相对路径或者是应用存档外部数据的绝对URL。
如果相同条目有多个单独节,则这些单独节中的属性会被合并。如果不同节中的相同属性有不同的值,则识别最后一个。
不理解的属性会被忽略。这些属性可能包含应用程序使用的实现特定信息。
2.清单文件规范
manifest-file: main-section newline *individual-section
main-section: version-info newline *main-attribute
version-info: Manifest-Version : version-number
version-number : digit+{.digit+}*
main-attribute: (any legitimate main attribute) newline
individual-section: Name : value newline *perentry-attribute
perentry-attribute: (any legitimate perentry attribute) newline
newline : CR LF | LF | CR (not followed by LF)
digit: {0-9}
在上面的规范中,可以出现在主节中的属性称为主属性,而可以出现在单独部分的属性称为每个条目的属性。某些属性可以同时出现在主节和单独节中,在这种情况下,每个条目的属性值会覆盖指定条目的主属性值。这两种类型的属性定义如下。
3.主属性
主属性是清单中出现在主节中的属性。他们可以分为以下几类:
1)一般主属性
Manifest-Version:定义清单版本。如上面规范所述,值是何方的版本号
Create-By:定义生成此清单文件的java实现版本和供应商。该属性由jar工具生成。
Signature-Version:定义jar文件的签名版本。该值应该是一个有效的版本号字符串。
Class-Path:此属性的值指定此应用程序或扩展所需的扩展名或依赖库的相对url。url由一个或多个空格分隔。应用程序或扩展类加载器使用此属性的值来构造其内部搜索路径。参见Class-Path属性。
2)为独立应用程序定义的属性
这个属性被捆绑到可执行jar文件中的独立应用程序使用,java运行时可以通过运行“java -jar x.jar”直接调用这些可执行jar文件。
Main-class:此属性的值是启动程序在启动时加载的主应用程序类的类名。该值不能将.class扩展追加到类名。
3)为applet定义的属性
弃用:这些属性和实现它的机制可能会在未来的版本中被删除。这些属性被绑定到JAR文件中的applet使用,以定义该appl