设置包版本信息
原文:
docs.oracle.com/javase/tutorial/deployment/jar/packageman.html
您可能需要在 JAR 文件的 MANIFEST.MF 中包含包版本信息。您可以使用 MANIFEST.MF 中的以下头部提供此信息:
清单中的头部
头部 | 定义 |
Name |
规范的名称。 |
Specification-Title |
规范的标题。 |
Specification-Version |
规范的版本。 |
Specification-Vendor |
规范的供应商。 |
Implementation-Title |
实现的标题。 |
Implementation-Version |
实现的构建编号。 |
Implementation-Vendor |
实现的供应商。 |
每个包可以分配一组这样的头部。版本头部应直接出现在包的Name
头部下方。此示例显示了所有版本头部:
Name: java/util/ Specification-Title: Java Utility Classes Specification-Version: 1.2 Specification-Vendor: Example Tech, Inc. Implementation-Title: java.util Implementation-Version: build57 Implementation-Vendor: Example Tech, Inc.
关于包版本头的更多信息,请参阅包版本规范。
一个示例
我们希望在 MyJar.jar 的 MANIFEST.MF 中包含上述示例中的头部。
首先创建一个名为Manifest.txt
的文本文件,内容如下:
Name: java/util/ Specification-Title: Java Utility Classes Specification-Version: 1.2 Specification-Vendor: Example Tech, Inc. Implementation-Title: java.util Implementation-Version: build57 Implementation-Vendor: Example Tech, Inc.
警告: 文本文件必须以新行或回车符结束。如果最后一行没有以新行或回车符结束,将无法正确解析最后一行。
然后通过输入以下命令创建名为MyJar.jar
的 JAR 文件:
jar cfm MyJar.jar Manifest.txt MyPackage/*.class
这将创建带有以下内容的 MANIFEST.MF 文件的 JAR 文件:
Manifest-Version: 1.0 Created-By: 1.7.0_06 (Oracle Corporation) Name: java/util/ Specification-Title: Java Utility Classes Specification-Version: 1.2 Specification-Vendor: Example Tech, Inc. Implementation-Title: java.util Implementation-Version: build57 Implementation-Vendor: Example Tech, Inc.
在 JAR 文件中封装包
原文:
docs.oracle.com/javase/tutorial/deployment/jar/sealman.html
JAR 文件中的包可以选择性地封装,这意味着该包中定义的所有类必须存档在同一个 JAR 文件中。例如,您可能希望封装一个包,以确保软件中的类之间的版本一致性。
通过在 MANIFEST.MF 中添加Sealed
头部来封装 JAR 文件中的包,其一般形式为:
Name: myCompany/myPackage/ Sealed: true
值myCompany/myPackage/
是要封装的包的名称。
请注意,包名必须以“/”结尾。
一个示例
我们想要在 JAR 文件MyJar.jar
中封装两个包firstPackage
和secondPackage
。
首先,我们创建一个名为Manifest.txt
的文本文件,内容如下:
Name: myCompany/firstPackage/ Sealed: true Name: myCompany/secondPackage/ Sealed: true
警告: 文本文件必须以新行或回车符结束。如果最后一行没有以新行或回车符结束,将无法正确解析最后一行。
然后,我们通过输入以下命令创建一个名为MyJar.jar
的 JAR 文件:
jar cfm MyJar.jar Manifest.txt MyPackage/*.class
这将创建一个带有以下内容的 MANIFEST.MF 文件的 JAR 文件:
Manifest-Version: 1.0 Created-By: 1.7.0_06 (Oracle Corporation) Name: myCompany/firstPackage/ Sealed: true Name: myCompany/secondPackage/ Sealed: true
封装 JAR 文件
如果要确保包中的所有类来自同一代码源,请使用 JAR 封装。封装的 JAR 指定该 JAR 定义的所有包都是封装的,除非在每个包的基础上进行覆盖。
要封装一个 JAR 文件,请使用值为 true 的Sealed
MANIFEST.MF 头部。例如,
Sealed: true
指定此存档中的所有包都是封装的,除非在 MANIFEST.MF 条目中使用Sealed
属性明确覆盖特定包。
使用清单属性增强安全性
原文:
docs.oracle.com/javase/tutorial/deployment/jar/secman.html
以下 JAR 文件清单属性可帮助确保您的 applet 或 Java Web Start 应用程序的安全性。只有Permissions
属性是必需的。
Permissions
属性用于确保应用程序仅请求在用于调用应用程序的 applet 标记或 JNLP 文件中指定的权限级别。使用此属性可帮助防止有人重新部署使用您的证书签名的应用程序,并以不同的特权级别运行。
此属性在主 JAR 文件的清单中是必需的。有关更多信息,请参阅 Java 平台标准版部署指南中的Permissions Attribute。Codebase
属性用于确保 JAR 文件的代码库受限于特定域。使用此属性可防止有人出于恶意目的在另一个网站上重新部署您的应用程序。有关更多信息,请参阅 Java 平台标准版部署指南中的Codebase Attribute。Application-Name
属性用于提供签名应用程序安全提示中显示的标题。有关更多信息,请参阅 Java 平台标准版部署指南中的Application-Name Attribute。Application-Library-Allowable-Codebase
属性用于标识您的应用程序预期被找到的位置。使用此属性可减少 JAR 文件位于不同位置时在安全提示中显示的位置数量。有关更多信息,请参阅 Java 平台标准版部署指南中的Application-Library-Allowable-Codebase Attribute。Caller-Allowable-Codebase
属性用于标识可以从中 JavaScript 代码调用您的应用程序的域。使用此属性可防止未知的 JavaScript 代码访问您的应用程序。有关更多信息,请参阅 Java 平台标准版部署指南中的Caller-Allowable-Codebase Attribute。Entry-Point
属性用于标识允许用作 RIA 入口点的类。使用此属性可防止未经授权的代码从 JAR 文件中的其他可用入口点运行。有关更多信息,请参阅 Java 平台标准版部署指南中的Entry-Point Attribute。Trusted-Only
属性用于防止加载不受信任的组件。有关更多信息,请参阅 Java 平台标准版部署指南中的Trusted-Only Attribute。Trusted-Library
属性用于允许特权 Java 代码和沙箱 Java 代码之间的调用,而无需提示用户进行权限确认。有关更多信息,请参阅 Java 平台标准版部署指南中的Trusted-Library Attribute。
有关如何将这些属性添加到清单文件中的信息,请参阅修改清单文件。
签署和验证 JAR 文件
原文:
docs.oracle.com/javase/tutorial/deployment/jar/signindex.html
您可以选择使用您的电子“签名”对 JAR 文件进行签名。验证您签名的用户可以授予您的 JAR 捆绑软件安全权限,这些权限通常是没有的。反之,您也可以验证您想要使用的已签名 JAR 文件的签名。
本课程将向您展示如何使用 JDK 提供的工具来签署和验证 JAR 文件:
理解签名和验证
如果您对签名和验证的概念不熟悉,本节将帮助您快速了解。它包含了相关术语的定义,签名提供的一些好处的解释,以及 Java 平台与 JAR 文件相关的签名机制的概要。
签署 JAR 文件
在这一部分,您将学习如何使用 JDK™工具对您的 JAR 文件进行数字签名。
验证已签名的 JAR 文件
本节将向您展示如何使用 JDK 工具集来验证已签名的 JAR 文件。
理解签署和验证
原文:
docs.oracle.com/javase/tutorial/deployment/jar/intro.html
Java™ 平台使你能够数字签名 JAR 文件。你数字签名一个文件的原因与你可能用钢笔在纸上签署文件的原因相同–让读者知道你写了这个文件,或者至少这个文件得到了你的批准。
当你签署一封信时,例如,所有认识你签名的人都可以确认你写了这封信。同样地,当你数字签名一个文件时,任何“认识”你数字签名的人都知道这个文件来自你。识别电子签名的过程称为验证。
当 JAR 文件被签名时,你还可以选择给签名加上时间戳。类似于在纸质文件上写日期,时间戳签名标识了 JAR 文件签名的时间。时间戳可用于验证签署 JAR 文件时使用的证书在签署时是有效的。
签署和验证文件的能力是 Java 平台安全架构的重要组成部分。安全性由运行时生效的安全策略控制。你可以配置策略以授予小程序和应用程序安全权限。例如,你可以授予小程序执行通常被禁止的操作的权限,如读写本地文件或运行本地可执行程序。如果你下载了由受信任实体签名的代码,你可以将这一事实作为决定为代码分配哪些安全权限的标准之一。
一旦你(或你的浏览器)验证了一个小程序来自受信任的来源,你可以让平台放宽安全限制,让小程序执行通常被禁止的操作。一个受信任的小程序可以根据运行时生效的策略文件拥有特定的自由。
Java 平台通过使用称为公钥和私钥的特殊数字来实现签署和验证。公钥和私钥是成对出现的,它们扮演互补的角色。
私钥是你可以用来签署文件的电子“笔”。顾名思义,你的私钥只有你知道,这样别人就无法“伪造”你的签名。用你的私钥签署的文件只能通过相应的公钥进行验证。
然而,仅有公钥和私钥还不足以真正验证一个签名。即使你已经验证了一个签名文件包含匹配的密钥对,你仍然需要一种方式来确认公钥确实来自它所声称来自的签署者。
因此,要使签名和验证工作,还需要另一个元素。这个额外的元素是签名者在签名的 JAR 文件中包含的证书。证书是来自被认可的认证机构的数字签名声明,指示谁拥有特定的公钥。认证机构是受到行业信任的实体(通常是专门从事数字安全的公司),它们负责为密钥及其所有者签署和发布证书。在签名的 JAR 文件中,证书指示谁拥有 JAR 文件中包含的公钥。
当您签署一个 JAR 文件时,您的公钥将与相关证书一起放置在存档中,以便任何想要验证您签名的人可以轻松使用。
总结数字签名:
- 签名者使用私钥对 JAR 文件进行签名。
- 相应的公钥与其证书一起放置在 JAR 文件中,以便任何想要验证签名的人可以使用。
摘要和签名文件
当您签署一个 JAR 文件时,存档中的每个文件都会在存档的清单中给出一个摘要条目。以下是这样一个条目可能看起来的示例:
Name: test/classes/ClassOne.class SHA1-Digest: TD1GZt8G11dXY2p4olSZPc5Rj64=
摘要值是文件内容的哈希值或编码表示,这些值是在签名时文件的内容。只有当文件本身发生变化时,文件的摘要值才会改变。
当对 JAR 文件进行签名时,会自动生成一个签名文件,并将其放置在 JAR 文件的META-INF
目录中,该目录与存档的清单文件位于同一目录中。签名文件的文件名具有.SF
扩展名。以下是签名文件内容的示例:
Signature-Version: 1.0 SHA1-Digest-Manifest: h1yS+K9T7DyHtZrtI+LxvgqaMYM= Created-By: 1.7.0_06 (Oracle Corporation) Name: test/classes/ClassOne.class SHA1-Digest: fcav7ShIG6i86xPepmitOVo4vWY= Name: test/classes/ClassTwo.class SHA1-Digest: xrQem9snnPhLySDiZyclMlsFdtM= Name: test/images/ImageOne.gif SHA1-Digest: kdHbE7kL9ZHLgK7akHttYV4XIa0= Name: test/images/ImageTwo.gif SHA1-Digest: mF0D5zpk68R4oaxEqoS9Q7nhm60=
如您所见,签名文件包含存档文件的摘要条目,这些条目看起来类似于清单中的摘要值条目。然而,清单中的摘要值是从文件本身计算出来的,而签名文件中的摘要值是从清单中的相应条目计算出来的。签名文件还包含整个清单的摘要值(请参见上面示例中的SHA1-Digest-Manifest
头)。
当验证已签名的 JAR 文件时,将重新计算每个文件的摘要,并将其与清单中记录的摘要进行比较,以确保 JAR 文件的内容自签名以来没有发生变化。作为额外的检查,还将重新计算清单文件本身的摘要值,并将其与签名文件中记录的值进行比较。
您可以在 JDK™文档的清单格式页面上阅读有关签名文件的其他信息。
签名块文件
除了签名文件外,当对 JAR 文件进行签名时,签名块文件会自动放置在META-INF
目录中。与清单文件或签名文件不同,签名块文件不是人类可读的。
签名块文件包含两个用于验证的关键元素:
- 使用签名者的私钥生成的 JAR 文件的数字签名
- 包含签名者公钥的证书,供任何想要验证已签名 JAR 文件的人使用
签名块文件的文件名通常会有一个.DSA
扩展名,表示它们是由默认数字签名算法创建的。如果使用与其他标准算法相关的密钥进行签名,则可能会有其他文件扩展名。
相关文档
有关密钥、证书和认证机构的其他信息,请参见
有关 Java 平台安全架构的更多信息,请参阅此相关文档:
- Java SE 中的安全功能
- Java SE 安全性
- 安全工具
签署 JAR 文件
原文:
docs.oracle.com/javase/tutorial/deployment/jar/signing.html
你使用 JAR 签名和验证工具来签署 JAR 文件并为签名加上时间戳。你通过使用 jarsigner
命令来调用 JAR 签名和验证工具,因此我们简称为 “Jarsigner”。
要签署一个 JAR 文件,你首先必须拥有一个私钥。私钥及其关联的公钥证书存储在受密码保护的数据库中,称为 keystores。一个 keystore 可以保存许多潜在签署者的密钥。keystore 中的每个密钥可以通过一个 alias 来标识,通常是拥有该密钥的签署者的名称。例如,属于 Rita Jones 的密钥可能具有别名 “rita”。
签署 JAR 文件的命令的基本形式是
jarsigner *jar-file alias*
在这个命令中:
jar-file
是要签署的 JAR 文件的路径名。alias
是标识要用于签署 JAR 文件和密钥关联证书的私钥的别名。
Jarsigner 工具会提示你输入 keystore 和别名的密码。
这个命令的基本形式假定要使用的 keystore 存储在你的主目录中名为 .keystore
的文件中。它将创建名称分别为 x.SF
和 x.DSA
的签名和签名块文件,其中 x
是别名的前八个字母,全部转换为大写。这个基本命令将覆盖原始 JAR 文件,用已签名的 JAR 文件替换。
在实践中,你可能希望使用其中一个或多个可用的命令选项。例如,鼓励为签名加上时间戳,以便部署应用程序的任何工具都可以验证用于签署 JAR 文件的证书在签署文件时是有效的。如果未包含时间戳,则 Jarsigner 工具会发出警告。
选项位于jar-file
路径名之前。以下表格描述了可用的选项:
Jarsigner 命令选项
选项 | 描述 |
-keystore url |
指定要使用的 keystore,如果你不想使用默认的 .keystore 数据库。 |
-sigfile file |
指定 .SF 和 .DSA 文件的基本名称,如果你不希望基本名称取自你的别名。 file 必须仅由大写字母(A-Z)、数字(0-9)、连字符(-)和下划线(_)组成。 |
-signedjar file |
指定要生成的已签名 JAR 文件的名称,如果你不希望原始未签名文件被已签名文件覆盖。 |
-tsa url |
使用由 URL 标识的时间戳机构(TSA)为签名生成时间戳。 |
-tsacert alias |
使用由 alias 标识的 TSA 的公钥证书为签名生成时间戳。 |
-altsigner class |
表示要使用另一种签名机制来时间戳签名。完全限定的类名标识所使用的类。 |
-altsignerpath classpathlist |
提供altsigner 选项标识的类的路径以及类所依赖的任何 JAR 文件。 |
示例
让我们看几个使用 Jarsigner 工具签署 JAR 文件的示例。在这些示例中,我们假设以下情况:
- 您的别名是"johndoe"。
- 您要使用的密钥库位于当前工作目录中名为"mykeys"的文件中。
- 您要用于时间戳签名的 TSA 位于
http://tsa.url.example.com
。
在这些假设下,您可以使用此命令对名为app.jar
的 JAR 文件进行签名:
jarsigner -keystore mykeys -tsa http://tsa.url.example.com app.jar johndoe
您将被提示输入密钥库和别名的密码。因为此命令不使用-sigfile
选项,因此创建的.SF 和.DSA 文件将命名为JOHNDOE.SF
和JOHNDOE.DSA
。因为该命令不使用-signedjar
选项,所以生成的签名文件将覆盖app.jar
的原始版本。
让我们看看如果您使用不同的选项组合会发生什么:
jarsigner -keystore mykeys -sigfile SIG -signedjar SignedApp.jar -tsacert testalias app.jar johndoe
签名和签名块文件将分别命名为SIG.SF
和SIG.DSA
,已签名的 JAR 文件SignedApp.jar
将放置在当前目录中。原始未签名的 JAR 文件将保持不变。此外,签名将使用 TSA 的公钥证书时间戳,标识为testalias
。
附加信息
JAR 签名和验证工具的完整参考页面在线查看:安全工具概述
**注意:**当证书是自签名时,应用程序的发布者将显示为UNKNOWN
。有关更多信息,请参阅从列为UNKNOWN
的发布者运行应用程序是否安全?。
验证已签名的 JAR 文件
原文:
docs.oracle.com/javase/tutorial/deployment/jar/verify.html
通常,验证已签名的 JAR 文件将由您的 Java™运行环境负责。您的浏览器将验证下载的已签名小程序。使用解释器的-jar
选项调用的已签名应用程序将由运行环境验证。
然而,您可以使用jarsigner
工具自行验证已签名的 JAR 文件。例如,您可能想要这样做来测试您准备的已签名 JAR 文件。
用于验证已签名的 JAR 文件的基本命令是:
jarsigner -verify *jar-file*
这个命令将验证 JAR 文件的签名,并确保存档中的文件在签名后没有发生变化。如果验证成功,您将看到以下消息:
jar verified.
如果您尝试验证一个未签名的 JAR 文件,将会出现以下消息:
jar is unsigned. (signatures missing or not parsable)
如果验证失败,将显示相应的消息。例如,如果 JAR 文件的内容自签名以来发生了变化,当您尝试验证文件时,将会出现类似以下消息:
jarsigner: java.lang.SecurityException: invalid SHA1 signature file digest for test/classes/Manifest.class
注意: 如果已签名的 JAR 文件使用了jdk.jar.disabledAlgorithms
安全属性中指定的任何算法(其中*java.home*
是您安装 JRE 的目录),JDK 将把已签名的 JAR 文件视为未签名。
使用与 JAR 相关的 API
原文:
docs.oracle.com/javase/tutorial/deployment/jar/apiindex.html
Java 平台包含几个用于处理 JAR 文件的类。其中一些 API 包括:
为了让您了解这些新 API 所打开的可能性,本课程将引导您了解一个名为 JarRunner 的示例应用程序的内部工作原理。
一个示例 - JarRunner 应用程序
JarRunner 允许您通过在命令行上指定 JAR 文件的 URL 来运行打包在 JAR 文件中的应用程序。例如,如果一个名为TargetApp
的应用程序被打包在http://www.example.com/TargetApp.jar
的 JAR 文件中,您可以使用以下命令运行该应用程序:
java JarRunner http://www.example.com/TargetApp.jar
为了使JarRunner
正常工作,它必须能够执行以下任务,所有这些任务都是通过使用新的 API 完成的:
- 访问远程 JAR 文件并与其建立通信链接。
- 检查 JAR 文件的清单,查看存档中哪个类是主类。
- 加载 JAR 文件中的类。
JarRunner
应用程序由两个类组成,JarRunner
和JarClassLoader
。JarRunner
将大部分 JAR 处理任务委托给JarClassLoader
类。JarClassLoader
扩展了java.net.URLClassLoader
类。在继续本课程之前,您可以查看JarRunner
和JarClassLoader
类的源代码:
JarRunner.java
JarClassLoader.java
本课程分为两部分:
JarClassLoader 类
本节展示了JarClassLoader
如何使用一些新的 API 来执行 JarRunner 应用程序所需的任务。
JarRunner 类
本节总结了包含JarRunner
应用程序的JarRunner
类。
JarClassLoader
类
原文:
docs.oracle.com/javase/tutorial/deployment/jar/jarclassloader.html
JarClassLoader
类扩展了java.net.URLClassLoader
。顾名思义,URLClassLoader
被设计用于加载通过搜索一组 URL 访问的类和资源。这些 URL 可以是目录或 JAR 文件。
除了继承URLClassLoader
,JarClassLoader
还利用了另外两个新的与 JAR 相关的 API 特性,即java.util.jar
包和java.net.JarURLConnection
类。在本节中,我们将详细查看JarClassLoader
的构造函数和两个方法。
JarClassLoader
构造函数
构造函数以java.net.URL
的实例作为参数。传递给这个构造函数的 URL 将在JarClassLoader
的其他地方使用,以找到要加载类的 JAR 文件。
public JarClassLoader(URL url) { super(new URL[] { url }); this.url = url; }
URL
对象被传递给父类URLClassLoader
的构造函数,该构造函数接受一个URL[]
数组作为参数,而不是单个URL
实例。
getMainClassName
方法
一旦使用 JAR 捆绑应用程序的 URL 构造了一个JarClassLoader
对象,它将需要一种方法来确定 JAR 文件中哪个类是应用程序的入口点。这就是getMainClassName
方法的工作:
public String getMainClassName() throws IOException { URL u = new URL("jar", "", url + "!/"); JarURLConnection uc = (JarURLConnection)u.openConnection(); Attributes attr = uc.getMainAttributes(); return attr != null ? attr.getValue(Attributes.Name.MAIN_CLASS) : null; }
你可能还记得之前的一节课中提到过,JAR 捆绑应用程序的入口点是由 JAR 文件清单的Main-Class
头部指定的。为了理解getMainClassName
如何访问Main-Class
头部的值,让我们详细看一下这个方法,特别关注它使用的新的 JAR 处理特性:
JarURLConnection
类和 JAR URL
getMainClassName
方法使用了java.net.JarURLConnection
类指定的 JAR URL 格式。JAR 文件的 URL 语法如下例所示:
jar:http://www.example.com/jarfile.jar!/
终止的!/
分隔符表示 URL 指向整个 JAR 文件。分隔符后面的任何内容都指向特定的 JAR 文件内容,就像这个例子中一样:
jar:http://www.example.com/jarfile.jar!/mypackage/myclass.class
getMainClassName
方法中的第一行是:
URL u = new URL("jar", "", url + "!/");
这个语句构造了一个新的URL
对象,表示一个 JAR URL,将JarClassLoader
实例创建时使用的 URL 后面添加了!/
分隔符。
java.net.JarURLConnection
类
这个类表示应用程序和 JAR 文件之间的通信链接。它有用于访问 JAR 文件清单的方法。getMainClassName
的第二行是:
JarURLConnection uc = (JarURLConnection)u.openConnection();
在这个语句中,第一行创建的URL
实例打开了一个URLConnection
。然后将URLConnection
实例转换为JarURLConnection
,以便利用JarURLConnection
的 JAR 处理特性。
获取清单属性:java.util.jar.Attributes
通过打开到 JAR 文件的JarURLConnection
,您可以使用JarURLConnection
的getMainAttributes
方法访问 JAR 文件 MANIFEST 中的头信息。此方法返回一个java.util.jar.Attributes
的实例,该类将 JAR 文件 MANIFEST 中的头名称与其关联的字符串值进行映射。getMainClassName
中的第三行创建了一个Attributes
对象:
Attributes attr = uc.getMainAttributes();
要获取 MANIFEST 的Main-Class
头的值,getMainClassName
的第四行调用了Attributes.getValue
方法:
return attr != null ? attr.getValue(Attributes.Name.MAIN_CLASS) : null;
方法的参数Attributes.Name.MAIN_CLASS
指定了您想要的Main-Class
头的值。(Attributes.Name
类还提供了静态字段,如MANIFEST_VERSION
、CLASS_PATH
和SEALED
,用于指定其他标准 MANIFEST 头。)
invokeClass 方法
我们已经看到JarURLClassLoader
如何在打包为 JAR 的应用程序中识别主类。要考虑的最后一个方法是JarURLClassLoader.invokeClass
,它使得可以调用主类来启动打包为 JAR 的应用程序:
public void invokeClass(String name, String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException { Class c = loadClass(name); Method m = c.getMethod("main", new Class[] { args.getClass() }); m.setAccessible(true); int mods = m.getModifiers(); if (m.getReturnType() != void.class || !Modifier.isStatic(mods) || !Modifier.isPublic(mods)) { throw new NoSuchMethodException("main"); } try { m.invoke(null, new Object[] { args }); } catch (IllegalAccessException e) { // This should not happen, as we have disabled access checks } }
invokeClass
方法接受两个参数:应用程序入口点类的名称和要传递给入口点类的main
方法的字符串参数数组。首先,加载主类:
Class c = loadClass(name);
loadClass
方法是从java.lang.ClassLoader
继承的。
一旦主类加载完成,就会使用java.lang.reflect
包的反射 API 将参数传递给类并启动它。您可以参考反射 API 上的教程来复习反射。
JarRunner
类
原文:
docs.oracle.com/javase/tutorial/deployment/jar/jarrunner.html
JarRunner
应用程序是以这种形式启动的:
java JarRunner *url [arguments]*
在前一节中,我们已经看到JarClassLoader
如何能够从给定的 URL 标识和加载 JAR 捆绑应用程序的主类。因此,要完成JarRunner
应用程序,我们需要能够从命令行获取 URL 和任何参数,并将它们传递给JarClassLoader
的实例。这些任务属于JarRunner
类,是JarRunner
应用程序的入口点。
它首先通过命令行指定的 URL 创建一个java.net.URL
对象:
public static void main(String[] args) { if (args.length < 1) { usage(); } URL url = null; try { url = new URL(args[0]); } catch (MalformedURLException e) { fatal("Invalid URL: " + args[0]); }
如果args.length < 1
,这意味着在命令行中没有指定 URL,因此会打印出使用消息。如果第一个命令行参数是一个有效的 URL,则会创建一个新的URL
对象来表示它。
接下来,JarRunner
创建了一个新的JarClassLoader
实例,并将在命令行中指定的 URL 传递给构造函数:
JarClassLoader cl = new JarClassLoader(url);
正如我们在前一节中看到的,通过JarClassLoader
,JarRunner
利用 JAR 处理 API。
传递给JarClassLoader
构造函数的 URL 是您想要运行的 JAR 捆绑应用程序的 URL。JarRunner
接下来调用类加载器的getMainClassName
方法来识别应用程序的入口点类:
String name = null; try { name = cl.getMainClassName(); } catch (IOException e) { System.err.println("I/O error while loading JAR file:"); e.printStackTrace(); System.exit(1); } if (name == null) { fatal("Specified jar file does not contain a 'Main-Class'" + " manifest attribute"); }
Java 中文官方教程 2022 版(十四)(2)https://developer.aliyun.com/article/1486374