打开的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 FrameworkSpecification-Title: Struts Framework
Specification-Vendor: Apache Software FoundationSpecification-Version: 1.1
Implementation-Title: Struts Framework
Implementation-Vendor: Apache Software FoundationImplementation-Vendor-Id: org.apacheImplementation-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.02. Created-By
声明该⽂件的⽣成者,⼀般该属性是由jar命令⾏⼯具⽣成的,例如:Created-By: Apache Ant 1.5.13. Signature-Version 定义jar⽂件的签名版本4. Class-Path
应⽤程序或者类装载器使⽤该值来构建内部的类搜索路径⼆. 应⽤程序相关属性
1. Main-Class
定义jar⽂件的⼊⼝类,该类必须是⼀个可执⾏的类,⼀旦定义了该属性即可通过 java -jar x.jar来运⾏该jar⽂件。
三. ⼩程序(Applet)相关属性
1. Extendsion-List
该属性指定了⼩程序需要的扩展信息列表,列表中的每个名字对应以下的属性2. 3. 1. Extension-Name 该属性定义了jar⽂件的标识,例如Extension-Name: Struts Framework 五. 包扩展属性 1. Implementation-Title 定义了扩展实现的标题2. Implementation-Version 定义扩展实现的版本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.classDigest-Algorithms: SHA MD5 SHA-Digest: AjR7RqnN//cdYGouxbd06mSVfI4=MD5-Digest: ZnTIQ2aQAtSNIOWXI1pQpw== 这段内容定义类签名的类名、计算摘要的名以及对应的摘要内容(使⽤BASE⽅法进⾏编码)七.⾃定义属性 除了前⾯提到的⼀些属性外,你也可以在MANIFEST.MF中增加⾃⼰的属性以及响应的值,例如J2ME程序jar包中就可能包含着如下信息关 键在于我们怎么来读取这些信息呢?其实很简单,JDK给我们提供了⽤于处理这些信息的API,详细的信息请见java.util.jar包中,我们可以通 过给JarFile传递⼀个jar⽂件的路径,然后调⽤JarFile的getManifest⽅法来获取Manifest信息。附: ⼤多数 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 ⽂件更快地装载,因为在装载过程中要解压缩⽂件,但是未压缩的⽂件在⽹络上的下载时间可能更长。META-INF ⽬录 ⼤多数 JAR ⽂件包含⼀个 META-INF ⽬录,它⽤于存储包和扩展的配置数据,如安全性和版本信息。2 平台识别并解释 META-INF ⽬录中的下述⽂件和⽬录,以便配置应⽤程序、扩展和类装载器: MANIFEST.MF。这个 manifest ⽂件定义了与扩展和包相关的数据。 INDEX.LIST。 这个⽂件由 jar ⼯具的新选项 -i ⽣成,它包含在应⽤程序或者扩展中定义的包的位置信息。它是 JarIndex 实现的⼀部分,并由类装载器⽤于加速类装载过程。 xxx.SF。 这是 JAR ⽂件的签名⽂件。占位符 xxx标识了签名者。 xxx.DSA。 与签名⽂件相关联的签名程序块⽂件,它存储了⽤于签名 JAR ⽂件的公共签名。jar ⼯具 为了⽤ JAR ⽂件执⾏基本的任务,要使⽤作为Development Kit 的⼀部分提供的 Java Archive Tool ( jar ⼯具)。⽤ jar 命令调⽤ jar ⼯具。表 1 显⽰了⼀些常见的应⽤:表 1. 常见的 jar ⼯具⽤法功能 ⽤⼀个单独的⽂件创建⼀个 JAR ⽂件⽤⼀个⽬录创建⼀个 JAR ⽂件创建⼀个未压缩的 JAR ⽂件更新⼀个 JAR ⽂件 查看⼀个 JAR ⽂件的内容 命令 jar cf jar-file input-file...jar cf jar-file dir-namejar cf0 jar-file dir-namejar uf jar-file input-file...jar tf jar-file 查看⼀个 JAR ⽂件的内容提取⼀个 JAR ⽂件的内容 从⼀个 JAR ⽂件中提取特定的⽂件 jar tf jar-filejar xf jar-file jar xf jar-file archived-file... 运⾏⼀个打包为可执⾏ JAR ⽂件的应⽤ java -jar app.jar 程序 可执⾏的 JAR ⼀个 可执⾏的 jar ⽂件是⼀个⾃包含的 Java 应⽤程序,它存储在特别配置的JAR ⽂件中,可以由 JVM 直接执⾏它⽽⽆需事先提取⽂件或者设置类路径。要运⾏存储在⾮可执⾏的 JAR 中的应⽤程序,必须将它加⼊到您的类路径中,并⽤名字调⽤应⽤程序的主类。但是使⽤可执⾏的 JAR ⽂件,我们可以不⽤提取它或者知道主要⼊⼝点就可以运⾏⼀个应⽤程序。可执⾏ JAR 有助于⽅便发布和执⾏ Java 应⽤程序。创建可执⾏ JAR 创建⼀个可执⾏ JAR 很容易。⾸先将所有应⽤程序代码放到⼀个⽬录中。假设应⽤程序中的主类是com.mycompany.myapp.Sample 。您要创建⼀个包含应⽤程序代码的 JAR ⽂件并标识出主类。为此,在某个位置(不是在应⽤程序⽬录中)创建⼀个名为 manifest 的⽂件,并在其中加⼊以下⼀⾏: Main-Class: com.mycompany.myapp.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.MFManifest-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.SFSignature-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 如果签名的 JAR ⽂件没有被篡改过,那么 jarsigner ⼯具就会告诉您 JAR 通过验证了。否则,它会抛出⼀个SecurityException , 表明哪些⽂件没有通过验证。 还可以⽤ java.util.jar 和 java.security API 以编程⽅式签名 JAR(有关细节参阅 )。也可以使⽤像Netscape Object Signing Tool 这样的⼯具。JAR 索引 如果⼀个应⽤程序或者 applet 捆绑到多个 JAR ⽂件中,那么类装载器就使⽤⼀个简单的线性搜索算法搜索类路径中的每⼀个元素,这使类装载器可能要下载并打开许多个 JAR ⽂件,直到找到所要的类或者资源。如果类装载器试图寻找⼀个不存在的资源,那么在应⽤程序或者 applet 中的所有 JAR ⽂件都会下载。对于⼤型的⽹络应⽤程序和 applet,这会导致启动缓慢、响应迟缓并浪费带宽。 从 JDK 1.3 以后,JAR ⽂件格式开始⽀持索引以优化⽹络应⽤程序中类的搜索过程,特别是 applet。JarIndex 机制收集在 applet 或者应⽤程序中定义的所有 JAR ⽂件的内容,并将这些信息存储到第⼀个 JAR ⽂件中的索引⽂件中。下载了第⼀个 JAR ⽂件后,applet 类装载器将使⽤收集的内容信息⾼效地装载 JAR ⽂件。这个⽬录信息存储在根 JAR ⽂件的 META-INF ⽬录中的⼀个名为 INDEX.LIST 的简单⽂本⽂件中。 创建⼀个 JarIndex 可以通过在 jar 命令中指定 -i 选项创建⼀个 JarIndex。假设我们的⽬录结构如下图所⽰: 图 2. JarIndex 您将使⽤下述命令为 JarIndex_Main.jar、JarIndex_test.jar 和 JarIndex_test1.jar 创建⼀个索引⽂件:jar -i JarIndex_Main.jar JarIndex_test.jar SampleDir/JarIndex_test1.jar INDEX.LIST ⽂件的格式很简单,包含每个已索引的 JAR ⽂件中包含的包或者类的名字,如清单 2 所⽰:清单 2. JarIndex INDEX.LIST ⽂件⽰例 JarIndex-Version: 1.0JarIndex_Main.jarsp JarIndex_test.jarSample SampleDir/JarIndex_test1.jarorgorg/apacheorg/apache/xerces org/apache/xerces/frameworkorg/apache/xerces/framework/xml4j 结束语 JAR 格式远远超出了⼀种压缩格式,它有许多可以改进效率、安全性和组织 Java 应⽤程序的功能。因为这些功能已经建⽴在核⼼平台 -- 包括编译器和类装载器 -- 中了,所以开发⼈员可以利⽤ JAR ⽂件格式的能⼒简化和改进开发和部署过程 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- azee.cn 版权所有 赣ICP备2024042794号-5
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务