MANIFEST.MF详解及配置的注意事项
⼀、详解
打开Java的JAR⽂件我们经常可以看到⽂件中包含着⼀个META-INF⽬录,这个⽬录下会有⼀些⽂件,其中必有⼀个MANIFEST.MF,这个⽂件描述了该Jar⽂件的很多信息,下⾯将详细介绍MANIFEST.MF⽂件的内容,先来看struts.jar中包含的MANIFEST.MF⽂件内容:
Manifest-Version: 1.0
Created-By: Apache Ant 1.5.1
Extension-Name: Struts Framework
Specification-Title: Struts Framework
Specification-Vendor: Apache Software Foundation
Specification-Version: 1.1
Implementation-Title: Struts Framework
Implementation-Vendor: Apache Software Foundation
Implementation-Vendor-Id: org.apache
Implementation-Version: 1.1
Class-Path:  commons-beanutils.jar commons-collections.jar commons-dig
ester.jar commons-logging.jar commons-validator.jar jakarta-oro.jar s
truts-legacy.jar
如果我们把MANIFEST中的配置信息进⾏分类,可以归纳出下⾯⼏个⼤类:
⼀. ⼀般属性
1. Manifest-Version
⽤来定义manifest⽂件的版本,例如:Manifest-Version: 1.0
2. Created-By
声明该⽂件的⽣成者,⼀般该属性是由jar命令⾏⼯具⽣成的,例如:Created-By: Apache Ant 1.5.1
3. Signature-Version
定义jar⽂件的签名版本
4. Class-Path
应⽤程序或者类装载器使⽤该值来构建内部的类搜索路径
⼆. 应⽤程序相关属性
1. Main-Class
定义jar⽂件的⼊⼝类,该类必须是⼀个可执⾏的类,⼀旦定义了该属性即可通过 java -jar x.jar来运⾏该jar⽂件。
三. ⼩程序(Applet)相关属性
1. Extendsion-List
该属性指定了⼩程序需要的扩展信息列表,列表中的每个名字对应以下的属性
2. <extension>-Extension-Name
3. <extension>-Specification-Version
4. <extension>-Implementation-Version
5. <extension>-Implementation-Vendor-Id
5. <extension>-Implementation-URL
四. 扩展标识属性
1. Extension-Name
该属性定义了jar⽂件的标识,例如Extension-Name: Struts Framework
五. 包扩展属性
1. Implementation-Title  定义了扩展实现的标题
2. Implementation-Version  定义扩展实现的版本
java创建文件
3. Implementation-Vendor  定义扩展实现的组织
4. Implementation-Vendor-Id  定义扩展实现的组织的标识
5. Implementation-URL :  定义该扩展包的下载地址(URL)
6. Specification-Title  定义扩展规范的标题
7. Specification-Version  定义扩展规范的版本
8. Specification-Vendor  声明了维护该规范的组织
9. Sealed  定义jar⽂件是否封存,值可以是true或者false (这点我还不是很理解)
六. 签名相关属性
签名⽅⾯的属性我们可以来参照JavaMail所提供的mail.jar中的⼀段
Name: javax/mail/Address.class
Digest-Algorithms: SHA MD5
SHA-Digest: AjR7RqnN//cdYGouxbd06mSVfI4=
MD5-Digest: ZnTIQ2aQAtSNIOWXI1pQpw==
这段内容定义类签名的类名、计算摘要的算法名以及对应的摘要内容(使⽤BASE⽅法进⾏编码)
七.⾃定义属性
除了前⾯提到的⼀些属性外,你也可以在MANIFEST.MF中增加⾃⼰的属性以及响应的值,例如J2ME程序jar包中就可能包含着如下信息
MicroEdition-Configuration: CLDC-1.0
MIDlet-Name: J2ME_MOBBER Midlet Suite
MIDlet-Info-URL: www.javayou
MIDlet-Icon: /icon.png
MIDlet-Vendor: Midlet Suite Vendor
MIDlet-1: mobber,/icon.png,mobber
MIDlet-Version: 1.0.0
MicroEdition-Profile: MIDP-1.0
MIDlet-Description: Communicator
关键在于我们怎么来读取这些信息呢?其实很简单,JDK给我们提供了⽤于处理这些信息的API,详细的信息请见java.util.jar包中,我们可以通过给JarFile传递⼀个jar⽂件的路径,然后调⽤JarFile的getManifest⽅法来获取Manifest信息。
更详细关于JAR⽂件的规范请见
java.sun/j2se/1.3/docs/guide/jar/jar.html
中⽂说明
www-900.ibm/developerWorks/cn/java/j-jar/
附:
⼤多数 Java 程序员都熟悉对 JAR ⽂件的基本操作。但是只有少数程序员了解 JAR ⽂件格式的强⼤功
能。在本⽂中,作者探讨了JAR 格式的许多功能和优势,包括打包、可执⾏的 JAR ⽂件、安全性和索引。
JAR ⽂件是什么?
JAR ⽂件格式以流⾏的 ZIP ⽂件格式为基础,⽤于将许多个⽂件聚集为⼀个⽂件。与 ZIP ⽂件不同的是,JAR ⽂件不仅⽤于压缩和发布,⽽且还⽤于部署和封装库、组件和插件程序,并可被像编译器和 JVM 这样的⼯具直接使⽤。在 JAR 中包含特殊的⽂件,如 manifests 和部署描述符,⽤来指⽰⼯具如何处理特定的 JAR。
⼀个 JAR ⽂件可以⽤于:
⽤于发布和使⽤类库
作为应⽤程序和扩展的构建单元
作为组件、applet 或者插件程序的部署单位
⽤于打包与组件相关联的辅助资源
JAR ⽂件格式提供了许多优势和功能,其中很多是传统的压缩格式如 ZIP 或者 TAR 所没有提供的。它们包括:
安全性。可以对 JAR ⽂件内容加上数字化签名。这样,能够识别签名的⼯具就可以有选择地为您授予软件安全特权,这是其他⽂件做不到的,它还可以检测代码是否被篡改过。
减少下载时间。如果⼀个 applet 捆绑到⼀个 JAR ⽂件中,那么浏览器就可以在⼀个 HTTP 事务中下载这个 applet 的类⽂件和相关的资源,⽽不是对每⼀个⽂件打开⼀个新连接。
压缩。JAR 格式允许您压缩⽂件以提⾼存储效率。
传输平台扩展。 Java 扩展框架(Java Extensions Framework)提供了向 Java 核⼼平台添加功能的⽅法,这些扩展是⽤ JAR ⽂件打包的(Java 3D 和 JavaMail 就是由 Sun 开发的扩展例⼦)。
包密封。存储在 JAR ⽂件中的包可以选择进⾏密封,以增强版本⼀致性和安全性。密封⼀个包意味着包中的所有类都必须在同⼀ JAR ⽂件中到。
包版本控制。⼀个 JAR ⽂件可以包含有关它所包含的⽂件的数据,如⼚商和版本信息。
可移植性。处理 JAR ⽂件的机制是 Java 平台核⼼ API 的标准部分。
压缩的和未压缩的 JAR
jar ⼯具(有关细节参阅 jar ⼯具 )在默认情况下压缩⽂件。未压缩的 JAR ⽂件⼀般可以⽐压缩过的 JAR ⽂件更快地装载,因为在装载过程中要解压缩⽂件,但是未压缩的⽂件在⽹络上的下载时间可能更长。
META-INF ⽬录
⼤多数 JAR ⽂件包含⼀个 META-INF ⽬录,它⽤于存储包和扩展的配置数据,如安全性和版本信息。Java 2 平台识别并解释 META-INF ⽬录中的下述⽂件和⽬录,以便配置应⽤程序、扩展和类装载器:
MANIFEST.MF。这个 manifest ⽂件定义了与扩展和包相关的数据。
INDEX.LIST。这个⽂件由 jar ⼯具的新选项 -i ⽣成,它包含在应⽤程序或者扩展中定义的包的位置信息。它是 JarIndex 实现的⼀部分,并
由类装载器⽤于加速类装载过程。
xxx.SF。这是 JAR ⽂件的签名⽂件。占位符 xxx标识了签名者。
xxx.DSA。与签名⽂件相关联的签名程序块⽂件,它存储了⽤于签名 JAR ⽂件的公共签名。
jar ⼯具
为了⽤ JAR ⽂件执⾏基本的任务,要使⽤作为Java Development Kit 的⼀部分提供的 Java Archive Tool ( jar ⼯具)。⽤ jar 命令调⽤ jar ⼯具。表 1 显⽰了⼀些常见的应⽤:
表 1. 常见的 jar ⼯具⽤法
功能
命令
⽤⼀个单独的⽂件创建⼀个 JAR ⽂件
jar cf
⽤⼀个⽬录创建⼀个 JAR ⽂件
jar cf jar-file dir-name
创建⼀个未压缩的 JAR ⽂件
jar cf0 jar-file dir-name
更新⼀个 JAR ⽂件
jar uf
查看⼀个 JAR ⽂件的内容
jar tf jar-file
提取⼀个 JAR ⽂件的内容
jar xf jar-file
从⼀个 JAR ⽂件中提取特定的⽂件
jar xf
运⾏⼀个打包为可执⾏ JAR ⽂件的应⽤程序
java -jar app.jar
可执⾏的 JAR
⼀个可执⾏的 jar ⽂件是⼀个⾃包含的 Java 应⽤程序,它存储在特别配置的JAR ⽂件中,可以由 JVM 直接执⾏它⽽⽆需事先提取⽂件或者设置类路径。要运⾏存储在⾮可执⾏的 JAR 中的应⽤程序,必须将它加⼊到您的类路径中,并⽤名字调⽤应⽤程序的主类。但是使⽤可执⾏的 JAR ⽂件,我们可以不⽤提取它或者知道主要⼊⼝点就可以运⾏⼀个应⽤程序。可执⾏ JAR 有助于⽅便发布和执⾏ Java 应⽤程序。
创建可执⾏ JAR
创建⼀个可执⾏ JAR 很容易。⾸先将所有应⽤程序代码放到⼀个⽬录中。假设应⽤程序中的主类是app.Sample 。您要创建⼀个包含应⽤程序代码的 JAR ⽂件并标识出主类。为此,在某个位置(不是在应⽤程序⽬录中)创建⼀个名为 manifest 的⽂件,并在其中加⼊以下⼀⾏:
Main-Class: app.Sample
然后,像这样创建 JAR ⽂件:
jar cmf manifest ExecutableJar.jar application-dir
所要做的就是这些了 -- 现在可以⽤ java -jar 执⾏这个 JAR ⽂件 ExecutableJar.jar。
⼀个可执⾏的 JAR 必须通过 menifest ⽂件的头引⽤它所需要的所有其他从属 JAR。如果使⽤了 -jar 选项,那么环境变量 CLASSPATH 和在命令⾏中指定的所有类路径都被 JVM 所忽略。
启动可执⾏ JAR
既然我们已经将⾃⼰的应⽤程序打包到了⼀个名为 ExecutableJar.jar 的可执⾏ JAR 中了,那么我们就可以⽤下⾯的命令直接从⽂件启动这个应⽤程序:
java -jar ExecutableJar.jar
包密封
密封 JAR ⽂件中的⼀个包意味着在这个包中定义的所有类都必须在同⼀个 JAR ⽂件中到。这使包的作者可以增强打包类之间的版本⼀致性。密封还提供了防⽌代码篡改的⼿段。
要密封包,需要在 JAR 的 manifest ⽂件中为包添加⼀个 Name 头,然后加上值为“true”的 Sealed 头。与可执⾏的 JAR ⼀样,可以在创
建 JAR 时,通过指定⼀个具有适当头元素的 manifest ⽂件密封⼀个 JAR,如下所⽰:
Name: com/samplePackage/
Sealed: true
Name 头标识出包的相对路径名。它以⼀个“/”结束以与⽂件名区别。在 Name 头后⾯第⼀个空⾏之前的所有头都作⽤于在 Name 头中指定的⽂件或者包。在上述例⼦中,因为 Sealed 头出现在 Name 头后并且中间没有空⾏,所以 Sealed 头将被解释为只应⽤到
包 com/samplePackage 上。
如果试图从密封包所在的 JAR ⽂件以外的其他地⽅装载密封包中的⼀个类,那么 JVM 将抛出⼀个SecurityException 。
扩展打包
扩展为 Java 平台增加了功能,在 JAR ⽂件格式中已经加⼊了扩展机制。扩展机制使得 JAR ⽂件可以通过manifest ⽂件中的 Class-Path 头指定所需要的其他 JAR ⽂件。
假设 extension1.jar 和 extension2.jar 是同⼀个⽬录中的两个 JAR ⽂件,extension1.jar 的 manifest ⽂件包含以下头:
Class-Path: extension2.jar
这个头表明 extension2.jar 中的类是 extension1.jar 中的类的扩展类。extension1.jar 中的类可以调⽤extension2.jar 中的类,并且不要
求 extension2.jar 处在类路径中。
在装载使⽤扩展机制的 JAR 时,JVM 会⾼效⽽⾃动地将在 Class-Path 头中引⽤的 JAR 添加到类路径中。不过,扩展 JAR 路径被解释为相对路径,所以⼀般来说,扩展 JAR 必须存储在引⽤它的 JAR 所在的同⼀⽬录中。
例如,假设类 ExtensionClient 引⽤了类 ExtensionDemo ,它捆绑在⼀个名为 ExtensionClient.jar 的 JAR ⽂件中,⽽类 ExtensionDemo 则捆绑在 ExtensionDemo.jar 中。为了使 ExtensionDemo.jar 可以成为扩展,必须将ExtensionDemo.jar 列
在 ExtensionClient.jar 的 manifest 的 Class-Path 头中,如下所⽰:
Manifest-Version: 1.0
Class-Path: ExtensionDemo.jar
在这个 manifest 中 Class-Path 头的值是没有指定路径的 ExtensionDemo.jar,表明 ExtensionDemo.jar 与ExtensionClient JAR ⽂件处在同⼀⽬录中。
JAR ⽂件中的安全性
JAR ⽂件可以⽤ jarsigner ⼯具或者直接通过 java.security API 签名。⼀个签名的 JAR ⽂件与原来的 JAR ⽂件完全相同,只是更新了它
的 manifest,并在 META-INF ⽬录中增加了两个⽂件,⼀个签名⽂件和⼀个签名块⽂件。
JAR ⽂件是⽤⼀个存储在 Keystore 数据库中的证书签名的。存储在 keystore 中的证书有密码保护,必须向jarsigner ⼯具提供这个密码才能对 JAR ⽂件签名。
图 1. Keystore 数据库
JAR 的每⼀位签名者都由在 JAR ⽂件的 META-INF ⽬录中的⼀个具有 .SF 扩展名的签名⽂件表⽰。这个⽂件的格式类似于 manifest ⽂件 -- ⼀组 RFC-822 头。如下所⽰,它的组成包括⼀个主要部分,它包括了由签名者提供的信息、但是不特别针对任何特定的 JAR ⽂件项,还有⼀系列的单独的项,这些项也必须包含在 menifest ⽂件中。在验证⼀个签名的 JAR 时,将签名⽂件的摘要值与对 JAR ⽂件中的相应项计算的摘要值进⾏⽐较。
清单 1. 签名 JAR 中的 Manifest 和 signature ⽂件
Contents of signature file META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.3.0 (Sun Microsystems Inc.)
Name: Sample.java
SHA1-Digest: 3+DdYW8INICtyG8ZarHlFxX0W6g=
Name: Sample.class
SHA1-Digest: YJ5yQHBZBJ3SsTNcHJFqUkfWEmI=
Contents of signature file META-INF/JAMES.SF
Signature-Version: 1.0
SHA1-Digest-Manifest: HBstZOJBuuTJ6QMIdB90T8sjaOM=
Created-By: 1.3.0 (Sun Microsystems Inc.)
Name: Sample.java
SHA1-Digest: qipMDrkurQcKwnyIlI3Jtrnia8Q=
Name: Sample.class
SHA1-Digest: pT2DYby8QXPcCzv2NwpLxd8p4G4=
数字签名
⼀个数字签名是.SF 签名⽂件的已签名版本。数字签名⽂件是⼆进制⽂件,并且与 .SF ⽂件有相同的⽂件名,但是扩展名不同。根据数字签名的类型 -- RSA、DSA 或者 PGP -- 以及⽤于签名 JAR 的证书类型⽽有不同的扩展名。
Keystore
要签名⼀个 JAR ⽂件,必须⾸先有⼀个私钥。私钥及其相关的公钥证书存储在名为 keystores 的、有密码保护的数据库中。JDK 包含创建和修改 keystores 的⼯具。keystore 中的每⼀个密钥都可以⽤⼀个别名标识,它通常是拥有这个密钥的签名者的名字。
所有 keystore 项(密钥和信任的证书项)都是⽤唯⼀别名访问的。别名是在⽤ keytool -genkey 命令⽣成密钥对(公钥和私钥)并在 keystore 中添加项时指定的。之后的 keytool 命令必须使⽤同样的别名引⽤这⼀项。
例如,要⽤别名“james”⽣成⼀个新的公钥/私钥对并将公钥包装到⾃签名的证书中,要使⽤下述命令:
keytool -genkey -alias james -keypass jamespass
-validity 80 -keystore jamesKeyStore
-storepass jamesKeyStorePass
这个命令序列指定了⼀个初始密码“jamespass”,后续的命令在访问 keystore “jamesKeyStore”中与别名“james”相关联的私钥时,就需要这个密码。如果 keystore“jamesKeyStore”不存在,则 keytool 会⾃动创建它。
jarsigner ⼯具
jarsigner ⼯具使⽤ keystore ⽣成或者验证 JAR ⽂件的数字签名。
假设像上述例⼦那样创建了 keystore “jamesKeyStore”,并且它包含⼀个别名为“james”的密钥,可以⽤下⾯的命令签名⼀个 JAR ⽂件:
jarsigner -keystore jamesKeyStore -storepass jamesKeyStorePass
-
keypass jamespass -signedjar SSample.jar Sample.jar james
这个命令⽤密码“jamesKeyStorePass”从名为“jamesKeyStore”的 keystore 中提出别名为“james”、密码为“jamespass”的密钥,并
对 Sample.jar ⽂件签名、创建⼀个签名的 JAR -- SSample.jar。
jarsigner ⼯具还可以验证⼀个签名的 JAR ⽂件,这种操作⽐签名 JAR ⽂件要简单得多,只需执⾏以下命令:
jarsigner -verify SSample.jar

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。