48、Java JAR文件的深入探索与实践

Java JAR文件的深入探索与实践

1. 查找类所在的JAR文件

在Java开发中,有时需要确定某个类位于哪个JAR文件中,或者找出包含特定类及其相关类的所有JAR文件。例如,执行相关操作时,可能会得到如下输出:

(inside c:\program files\java\jdk1.6.0\jre\lib\rt.jar)
java/security/spec/RSAPrivateKeySpec.class
(inside c:\program files\java\jdk1.6.0\jre\lib\rt.jar)
sun/security/rsa/RSAPrivateKeyImpl.class

这表明 RSAPrivateKey 或相关类位于 c:\program files\java\jdk1.6.0\jre\lib\rt.jar 文件中。若搜索更生僻的类,如 ByteToCharDBCS_EBCDIC ,搜索结果中会找到 charsets.jar 文件。利用该功能,不仅能找到类所在的JAR文件,还能找出包含该类的所有JAR文件,有助于解决类路径混乱的问题。

2. 探索认可目录

在Java运行时环境(JRE)的安装中,存在一些不属于标准Java API的包,这些包通常是常见的第三方库,被视为认可包,即作为Java API的扩展进行分发。例如, org.omg.CORBA 包提供了CORBA功能。由于这些包可供Java程序使用,当分发已存在于认可目录中的第三方库时,可能会发生冲突。

Java提供了认可标准覆盖机制,允许在认可目录中安装库的较新版本。要覆盖认可标准,可将JAR文件放置在JRE内的 endorsed 目录中。该目录在Windows和Unix系统中都位于JRE安装目录下的 lib 目录内。若安装了多个JRE或JDK,需确保将JAR文件放置在正确的认可目录中,以便执行的虚拟机能够识别这些JAR文件。若想使用不同的目录来覆盖认可标准,可在 java.endorsed.dirs 系统属性中指定。在该属性中,可列出一个或多个包含所需JAR文件的目录,目录之间用 File.pathSeparatorChar 分隔,该分隔符因系统而异。

以下是可被覆盖的标准API包列表:
| 可覆盖的包 |
| — |
| javax.rmi.CORBA |
| org.omg.DynamicAny |
| org.omg.CORBA |
| org.omg.DynamicAny.DynAnyFactoryPackage |
| org.omg.CORBA.DynAnyPackage |
| org.omg.DynamicAny.DynAnyPackage |
| org.omg.CORBA.ORBPackage |
| org.omg.IOP |
| org.omg.CORBA.portable |
| org.omg.IOP.CodecFactoryPackage |
| org.omg.CORBA.TypeCodePackage |
| org.omg.IOP.CodecPackage |
| org.omg.CORBA_2_3 |
| org.omg.Messaging |
| org.omg.CORBA_2_3.portable |
| org.omg.PortableInterceptor |
| org.omg.CosNaming |
| org.omg.PortableInterceptor.ORBInitInfoPackage |
| org.omg.CosNaming.Naming |
| org.omg.PortableServer.ContextExtPackage |
| org.omg.PortableServer.CurrentPackage |
| org.omg.CosNaming.Naming.ContextPackage |
| org.omg.Dynamic |

3. 探索Java归档文件(JAR)

Java的成功离不开其归档文件格式的创建。Java归档文件(JAR)是一种将多个文件(包括其他JAR文件)打包成一个以 .jar 为扩展名的单个文件的方式。JAR文件使用与zip格式相同的文件压缩方式,因此可以在支持zip压缩的程序中打开和编辑JAR文件,这使得JAR文件格式在不同操作系统之间具有可移植性,因为大多数操作系统都支持zip格式或有操作zip文件的工具。

JAR文件通过压缩类、图像、音频和其他大文件,可大大减少它们的下载时间。例如,小程序及其资源可以压缩到一个JAR文件中,显著减少小程序的下载时间。

JAR文件还可以进行数字签名,以满足对应用程序有较高安全要求的架构。通过对JAR文件进行数字签名,可以确定文件的作者以及文件是否被篡改。Java 5引入了两项JAR支持的新增强功能:
- 通过在命令行JAR工具中添加新参数 -i ,实现了对JAR文件内容的更快访问,该参数允许创建JAR文件索引。
- 增加了一个用于在打开JAR文件时使用的“关闭时删除”模式的新API。

JAR文件与普通zip文件的主要区别在于其包含的清单文件,该文件位于JAR文件的 META-INF 目录中。清单文件允许调用特殊功能,如包密封和将JAR指定为可执行JAR文件。清单文件的格式类似于属性文件,接受键值对条目,用于更改JAR文件的特定设置。除了清单文件,JAR文件的 META-INF 目录中还可以创建其他文件。通过索引支持,可以在 META-INF 目录中包含一个 INDEX.LIST 文件,当调用JAR工具并指定 -i 选项时,该文件会自动生成,从而加快类加载时间。

4. 操作JAR文件

JDK包含一个名为 jar 的命令行工具,用于通过命令行创建JAR文件。在控制台窗口中输入 jar 即可执行该工具。若工具无法运行,可能是Java环境配置不正确,需重新阅读JDK的安装说明。虽然也可以从 JDK/BIN 目录运行该工具,但建议调整环境变量,以便在任何位置都能运行该工具。

执行 jar 工具的正确语法如下:

jar {ctxu}[vfm0Mi] [jar-file] [manifest-file] [-C dir] files ...

在创建第一个JAR文件之前,了解可用于创建JAR文件的选项非常重要。以下是 jar 工具的选项及其说明:
| 选项 | 描述 |
| — | — |
| c | 用于创建新的归档文件 |
| t | 列出归档文件的目录内容,是创建JAR文件后检查其内容是否成功创建且符合预期的好方法。通常将 f 选项与 t 选项结合使用,以减少输入量 |
| x | 用于从JAR文件中提取指定文件或所有文件 |
| u | 允许使用指定的新文件或更改后的文件更新JAR文件。由于更新大量文件时此任务可能很繁琐,因此更可能使用了解如何更新zip文件格式的工具或集成开发环境(IDE)来更新JAR文件 |
| v | 详细选项,在创建JAR文件时可从 jar 工具获得更多反馈,有助于调试问题 |
| f | 指定要更新的JAR文件在命令行中 |
| m | 表示向 jar 工具提供要包含在JAR文件中的清单文件 |
| 0 | 零选项,告诉 jar 工具不压缩文件,仅将它们打包到归档文件中 |
| M | 阻止创建默认的清单文件。清单文件在JAR文件中是可选的 |
| i | Java 5引入的选项,用于在JAR文件的 META-INF 目录下生成名为 INDEX.LIST 的索引信息 |
| C [DIR] | 指示 jar 工具将目录更改为指定的目录,并对引用的文件进行JAR打包 |

以下是一个创建JAR文件的示例,该JAR文件包含两个Java文件和一个 images 目录:

C:\>jar -cvf chess.jar chess
added manifest
adding: chess/(in = 0) (out= 0)(stored 0%)
adding: chess/Chess.java(in = 0) (out= 0)(stored 0%)
adding: chess/ChessGUI.java(in = 0) (out= 0)(stored 0%)
adding: chess/images/(in = 0) (out= 0)(stored 0%)
adding: chess/images/board.bmp(in = 0) (out= 0)(stored 0%)

该命令将 C:\chess 目录及其所有子目录压缩到 chess.jar 文件中。 jar 工具会在JAR文件的 META-INF 目录中自动生成一个默认的清单文件,其中仅包含一个版本字符串。

要查看JAR文件的内容,可使用 t 选项:

C:\>jar -tf chess.jar
META-INF/
META-INF/MANIFEST.MF
chess/
chess/Chess.java
chess/ChessGUI.java
chess/images/
chess/images/board.bmp

若需要解压缩JAR文件以修补或编辑其中的文件,可使用 x 选项。以下示例使用了 xvf 选项:

C:\>jar -xvf chess.jar
created: META-INF/
inflated: META-INF/MANIFEST.MF
created: chess/
extracted: chess/Chess.java
extracted: chess/ChessGUI.java
created: chess/images/
extracted: chess/images/board.bmp 

该命令将JAR文件提取到当前工作目录,之后可根据需要编辑文件并重新打包。

5. 检查基本清单文件

清单文件可视为包含其所属JAR文件元数据信息的文件。通过使用清单文件,可以对JAR文件、包和扩展进行版本控制、数字签名和密封。首次创建JAR文件时,若未指定 -M 选项,将自动创建一个默认的清单文件。默认清单文件的内容可能如下所示,具体取决于所使用的Java版本:

Manifest-Version: 1.0
Created-By: 1.6.0-rc (Sun Microsystems Inc.)

清单文件分为两个主要部分:主部分和个体部分,可在个体部分列出不同文件或包的信息。不必在清单文件中列出JAR文件中的每个文件,除非计划对JAR文件中的特定文件进行签名,此时必须列出这些文件。

清单中的信息按键值对条目分隔,使用冒号( : )字符分隔键和值,这与属性文件类似,但属性文件使用等号( = )作为分隔符。Java无法理解的任何属性将被忽略,但这些属性仍可由应用程序使用,因此这些属性有时被称为特定于应用程序的属性。以下是一些常见的主要属性及其简要说明:
| 属性 | 描述 |
| — | — |
| Manifest-Version | 该属性的值是清单文件的版本 |
| Created-By | 由 jar 工具生成,是用于创建JAR的Java版本,还包括创建Java实现的供应商名称 |
| Signature-Version | 该属性的值包含JAR文件的签名版本,必须包含具有特定格式的有效版本号字符串:digit+{.digit+}* |
| Class-Path | 类加载器使用该值创建内部搜索路径,以查找应用程序所需的扩展或库。URL之间用空格分隔 |
| Main-Class | 创建自执行JAR文件时需要该属性,需指定包含 main 方法的类文件的名称。指定名称时,不要包含 .class 扩展名,否则JAR文件将无法执行 |
| Sealed | 该属性只有两个可能的值: true false 。若为 true ,则JAR文件中的所有包都将被密封,除非单独定义为不同的情况。若密封,类加载器将仅从JAR文件中加载与从JAR文件中加载的第一个类属于同一包的类 |

虽然清单文件可能不是一个令人兴奋的文件,但探索它有助于全面了解其为JAR文件提供的强大功能和灵活性。

6. 检查小程序和JAR文件

JAR文件最常见的用途之一是将小程序代码打包到JAR文件中,并通过Web浏览器像访问其他小程序一样访问它们。由于这一特性,清单中的一个特殊属性(扩展属性)可用于在小程序中包含其他包。

以下是可用于优化小程序的扩展属性列表:
| 属性 | 描述 |
| — | — |
| Extension-List | 列出希望包含在小程序中的可选包,包名之间用单个空格分隔 |
| (extension)-Extension-Name | 存储Java插件用于确定包是否已安装的包的唯一名称 |
| (extension)-Specification-Version | 告知Java插件使用该包所需的最低版本 |
| (extension)-Implementation-Version | 告知Java插件所需的包的最低实现版本。若版本过旧,插件将尝试下载该包的较新版本 |
| (extension)-Implementation-Vendor-Id | 用于为可选包分配供应商ID。Java插件将比较供应商ID,以确保获取正确的可选包 |
| (extension)-Implementation-URL | 为了让Java插件知道在哪里获取包的最新版本,必须将该属性设置为告知Java插件从何处下载最新可选包的URL |

7. 签署JAR文件

对于注重安全的应用程序,签署JAR文件非常重要,它可以确保JAR文件未被篡改且来自原始作者。JAR文件可以使用名为 jarsigner 的特殊实用工具进行签名,该工具位于 JAVA_HOME/BIN 目录中。也可以通过代码使用 java.security API对JAR文件进行签名。

jarsigner 工具通过访问由 keytool 实用工具创建的密钥库来签署JAR文件。 keytool 用于创建公钥和私钥、发出证书请求、导入证书回复以及确定第三方的公钥是否可信。 jarsigner 工具使用私钥对JAR文件进行签名,只有知道私钥密码的人才能使用该私钥签署JAR文件。

jarsigner 工具对JAR文件进行签名时, META-INF 目录中的所有条目都会被签名,甚至与签名无关的文件也会被签名。一般来说,与签名相关的文件以以下扩展名结尾: *.RSA *.SF *.DSA SIG-*

使用 java.security API签署JAR文件比使用 jarsigner 工具要复杂得多。当JAR文件成功签署后,它必须包含更新后的清单文件、签名文件和签名块文件。在清单文件中会为每个签署的文件创建条目,示例如下:

Name: com/wrox/SampleSigned.class
SHA1-Digest: fcavHwerE23Ff4355fdsMdS=

以下是一个具体的示例,展示了如何使用 keytool 生成密钥库并创建自签名测试证书,然后使用 jarsigner 工具对之前创建的 chess.jar 文件进行签名:

7.1 生成密钥库

  1. 执行以下命令创建一个包含密钥的 myKeystore 文件:
C:\>keytool -genkey -keystore myKeystore -alias myself
  1. 提示输入密钥库密码时,输入 password
Enter keystore password:  password
  1. 接下来,按以下内容填写个人信息:
What is your first and last name?
[Unknown]:  John Doe
What is the name of your organizational unit?
[Unknown]:  IT
What is the name of your organization?
[Unknown]:  Wrox
What is the name of your City or Locality?
[Unknown]:  Springfield
What is the name of your State or Province?
[Unknown]:  Ohio
What is the two-letter country code for this unit?
[Unknown]:  US
Is CN=John Doe, OU=IT, O=Wrox, L=Springfield, ST=Ohio, C=US correct?
[no]:  Yes
  1. 最后,输入私钥密码,再次输入 password
Enter key password for <myself>
(RETURN if same as keystore password):  password

7.2 生成自签名证书

执行以下命令生成自签名证书:

C:\>keytool -selfcert -alias myself -keystore myKeystore

该命令会提示输入密钥库密码,输入之前设置的 password 。此命令可能需要一两分钟才能完成,具体取决于系统性能。

7.3 验证密钥库和证书

执行以下命令查看密钥库的内容:

C:\>keytool -list -keystore myKeystore
Enter keystore password:  password

输入密码后,输出示例如下:

Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
myself, Jul 21, 2004, keyEntry,
Certificate fingerprint (MD5): 96:0B:2C:20:EA:DB:87:7A:64:DA:9F:68:21:85:B6:9A

若得到上述输出,则表示可以使用该密钥库和证书对JAR文件进行签名。

7.4 签署JAR文件

执行以下命令使用 jarsigner 工具签署 chess.jar 文件:

C:\>jarsigner -keystore myKeystore chess.jar myself
Enter Passphrase for keystore: password
Warning: The signer certificate will expire within six months.

7.5 验证签名

签署成功后,可通过以下两种方式验证JAR文件的签名:
- 提取JAR文件并查看其内容,应该会看到两个新文件: Myself.dsa Myself.sf .dsa (数字签名)文件不可读,但 .sf 文件可以读取,其内容示例如下:

Signature-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
SHA1-Digest-Manifest-Main-Attributes: XpKykodQ7e3bKKW8wqLFO8VocOU=
SHA1-Digest-Manifest: eL4xJ2eU5oyO7h4VVYW0hs1pEj0=
Name: chess/images/board.bmp
SHA1-Digest: wvxwx9Dqd+jbKoe8e7raVxSfNzI=
Name: chess/ChessGUI.java
SHA1-Digest: JlWKkQ9l5/82bHxMdf4nzrmphH0=
Name: chess/Chess.java
SHA1-Digest: Y4jUlkFH64RojRERTRBEIZRC+uc=

这些新条目显示了 jarsigner 为每个签署的文件生成的签名,这些条目也会显示在 manifest.mf 文件中。
- 使用 jarsigner 工具的 -verify 选项验证JAR文件的签名:

C:\>jarsigner -verbose -verify chess.jar

若验证成功,将看到以下输出:

289 Wed July 21 21:28:58 EDT 2004 META-INF/MANIFEST.MF
410 Wed July 21 21:28:58 EDT 2004 META-INF/MYSELF.SF
1008 Wed July 21 21:28:58 EDT 2004 META-INF/MYSELF.DSA
0 Wed July 21 13:36:18 EDT 2004 META-INF/
0 Wed July 21  13:27:02 EDT 2004 chess/
sm         0 Wed July 21  13:26:32 EDT 2004 chess/Chess.java
sm         0 Wed July 21  13:26:42 EDT 2004 chess/ChessGUI.java
0 Wed July 21 13:27:14 EDT 2004 chess/images/
sm         0 Wed July 21 13:27:08 EDT 2004 chess/images/board.bmp
s = signature was verified
m = entry is listed in manifest
k = at least one certificate was found in keystore
i = at least one certificate was found in identity scope
jar verified.

若验证失败, jarsigner 工具将抛出安全异常,或者若JAR文件根本未签名,将返回消息表明JAR文件未签名(签名缺失或无法解析)。

JAR文件还可以由多个人进行签名,每个人运行 jarsigner 工具生成的签名都会存储在 META-INF 目录中,就像一个人签名的情况一样。甚至可以使用不同版本的JDK对JAR文件进行签名,通过上述用于签署JAR文件和创建密钥库的工具,可以实现多种安全选项。

在结束之前,让我们仔细看看 jarsigner 工具可以使用的选项:
| 选项 | 描述 |
| — | — |
| keystore | 签署JAR文件时必需,若未指定要使用的密钥库文件,将默认使用用户主目录下的 .keystore 文件。可以为 URL 参数指定密钥库文件的完整路径和文件名 |
| storepass | 用于提供访问计划在签署JAR文件时使用的密钥库所需的密码 |
| storetype | 用于指定要使用的密钥库类型。 security.properties 文件中有一个名为 keystore.type 的条目,若未提供 storetype jarsigner 工具将默认使用该值 |
| keypass | 若私钥密码与密钥库密码不同,则需要提供该密码。若未提供此选项,必要时将提示输入密码 |
| sigfile | 指定用于生成 .sf .dsa 文件的文件名的基础部分。此选项允许覆盖 jarsigner 工具生成的默认值 |

通过以上步骤和工具,你可以全面掌握Java JAR文件的操作和安全签名,确保在开发和部署Java应用程序时能够高效、安全地使用JAR文件。

8. 总结与最佳实践

8.1 关键要点回顾
  • JAR文件基础 :JAR文件是Java中重要的归档文件格式,它将多个文件打包成一个以 .jar 为扩展名的文件,使用与zip相同的压缩方式,具有可移植性。能减少文件下载时间,还可进行数字签名以保障安全。
  • 清单文件 :位于 META-INF 目录的清单文件是JAR文件的重要组成部分,可用于版本控制、数字签名、包密封等,包含主部分和个体部分,通过键值对设置JAR文件属性。
  • 操作工具 jar 工具用于创建、查看、提取和更新JAR文件; keytool 用于生成密钥库和证书; jarsigner 用于签署JAR文件。
8.2 最佳实践建议
  • JAR文件创建 :在创建JAR文件时,合理使用 jar 工具的选项。例如,使用 -cvf 选项创建并详细输出创建过程,使用 -i 选项创建索引以加快类加载。
  • 清单文件配置 :根据需求配置清单文件的属性。如创建可执行JAR文件时,设置 Main-Class 属性;需要引用外部库时,设置 Class-Path 属性。
  • 安全签名 :对于需要安全保障的JAR文件,务必进行数字签名。使用 keytool 生成安全的密钥库和证书,使用 jarsigner 进行签名,并定期验证签名的有效性。

9. 常见问题与解决方案

9.1 类路径问题
  • 问题描述 :在使用JAR文件时,可能会遇到类路径混乱的问题,导致程序无法找到所需的类。
  • 解决方案
    • 检查 Class-Path 属性:确保清单文件中的 Class-Path 属性正确列出了所需的JAR文件和目录。
    • 检查环境变量:确保 CLASSPATH 环境变量包含了所有必要的JAR文件和目录。
    • 使用绝对路径:在引用JAR文件时,尽量使用绝对路径,避免相对路径带来的问题。
9.2 签名验证失败
  • 问题描述 :使用 jarsigner -verify 验证JAR文件签名时,可能会出现验证失败的情况。
  • 解决方案
    • 检查证书有效期:确保签名使用的证书未过期,若证书即将过期,及时更新证书。
    • 检查密钥库密码:确保在签署和验证JAR文件时使用的密钥库密码正确。
    • 检查JAR文件完整性:确保JAR文件在传输或存储过程中未被篡改。
9.3 JAR文件无法执行
  • 问题描述 :创建的可执行JAR文件无法正常执行。
  • 解决方案
    • 检查 Main-Class 属性:确保清单文件中的 Main-Class 属性正确指定了包含 main 方法的类,且不包含 .class 扩展名。
    • 检查依赖库:确保JAR文件中包含了所有必要的依赖库,或者在 Class-Path 属性中正确列出了外部依赖库。

10. 未来趋势与展望

10.1 技术发展趋势
  • 性能优化 :未来JAR文件的处理性能可能会进一步提升,例如更高效的压缩算法、更快的类加载机制。
  • 安全增强 :随着安全需求的不断增加,JAR文件的数字签名技术可能会更加完善,提供更高级别的安全保障。
  • 与容器技术集成 :随着容器技术的广泛应用,JAR文件可能会更好地与容器化环境集成,实现更便捷的部署和管理。
10.2 对开发者的影响
  • 学习成本 :开发者需要不断学习新的技术和工具,以跟上JAR文件技术的发展。
  • 开发效率 :更高效的JAR文件处理技术将提高开发者的开发效率,减少部署和调试时间。
  • 安全意识 :开发者需要更加重视JAR文件的安全问题,采取有效的安全措施保障应用程序的安全。

11. 总结

通过本文的介绍,我们全面了解了Java JAR文件的相关知识,包括JAR文件的创建、操作、清单文件的配置、数字签名等。掌握这些知识和技能,能够帮助我们在Java开发和部署过程中更加高效、安全地使用JAR文件。同时,我们也了解了JAR文件技术的未来发展趋势,为我们在未来的开发工作中提供了方向。希望本文能够对广大Java开发者有所帮助,让我们在Java的世界中创造出更加优秀的应用程序。

附录:JAR文件操作流程图

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B(创建JAR文件):::process
    B --> C{是否需要签名?}:::decision
    C -->|是| D(生成密钥库和证书):::process
    D --> E(签署JAR文件):::process
    C -->|否| F(使用JAR文件):::process
    E --> F
    F --> G{是否需要更新?}:::decision
    G -->|是| H(更新JAR文件):::process
    H --> F
    G -->|否| I(验证JAR文件签名):::process
    I --> J(结束使用JAR文件):::process
    J --> K([结束]):::startend

附录:JAR文件操作命令总结表

操作 命令示例 说明
创建JAR文件 jar -cvf chess.jar chess 创建 chess.jar 文件,包含 chess 目录及其子目录
查看JAR文件内容 jar -tf chess.jar 列出 chess.jar 文件的内容
提取JAR文件 jar -xvf chess.jar chess.jar 文件提取到当前目录
生成密钥库 keytool -genkey -keystore myKeystore -alias myself 生成名为 myKeystore 的密钥库,别名 myself
生成自签名证书 keytool -selfcert -alias myself -keystore myKeystore myKeystore 中的 myself 别名生成自签名证书
签署JAR文件 jarsigner -keystore myKeystore chess.jar myself 使用 myKeystore 中的证书签署 chess.jar 文件
验证JAR文件签名 jarsigner -verbose -verify chess.jar 验证 chess.jar 文件的签名
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值