Java 中文官方教程 2022 版(十四)(1)

简介: Java 中文官方教程 2022 版(十四)

设置包版本信息

原文: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中封装两个包firstPackagesecondPackage

首先,我们创建一个名为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 平台安全架构的更多信息,请参阅此相关文档:

签署 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.SFx.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.SFJOHNDOE.DSA。因为该命令不使用-signedjar选项,所以生成的签名文件将覆盖app.jar的原始版本。

让我们看看如果您使用不同的选项组合会发生什么:

jarsigner -keystore mykeys -sigfile SIG -signedjar SignedApp.jar 
          -tsacert testalias app.jar johndoe

签名和签名块文件将分别命名为SIG.SFSIG.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应用程序由两个类组成,JarRunnerJarClassLoaderJarRunner将大部分 JAR 处理任务委托给JarClassLoader类。JarClassLoader扩展了java.net.URLClassLoader类。在继续本课程之前,您可以查看JarRunnerJarClassLoader类的源代码:

  • 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 文件。

除了继承URLClassLoaderJarClassLoader还利用了另外两个新的与 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,您可以使用JarURLConnectiongetMainAttributes方法访问 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_VERSIONCLASS_PATHSEALED,用于指定其他标准 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);

正如我们在前一节中看到的,通过JarClassLoaderJarRunner利用 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

相关文章
|
22小时前
|
Oracle Java 关系型数据库
Java官网下载JDK21版本详细教程(下载、安装、环境变量配置)
Java官网下载JDK21版本详细教程(下载、安装、环境变量配置)
|
1天前
|
Java 测试技术 Python
《手把手教你》系列基础篇(七十七)-java+ selenium自动化测试-框架设计基础-TestNG依赖测试- 上篇(详解教程)
【6月更文挑战第18天】TestNG是一个Java测试框架,它允许在测试方法间定义执行顺序和依赖关系。当不指定依赖时,TestNG默认按方法名首字母排序执行。`@Test`注解的`dependsOnMethods`属性用于指定方法依赖,如`test1`依赖`test4`,则实际执行顺序为`test4`、`test2`、`test3`、`test1`。如果依赖的方法失败,后续依赖的方法将被跳过。此外,`dependsOnGroups`属性通过组名指定依赖,方便管理多个相关测试方法。通过`groups`定义方法所属组,然后在其他方法中用`dependsOnGroups`引用这些组。
16 5
|
2天前
|
存储 测试技术 数据安全/隐私保护
《手把手教你》系列基础篇(七十六)-java+ selenium自动化测试-框架设计基础-TestNG实现DDT - 下篇(详解教程)
【6月更文挑战第17天】本文是一篇关于使用Selenium和TestNG进行数据驱动测试的教程。作者宏哥通过实例展示了如何处理多个用户登录场景。
37 0
|
3天前
|
XML 测试技术 数据格式
《手把手教你》系列基础篇(七十五)-java+ selenium自动化测试-框架设计基础-TestNG实现DDT - 中篇(详解教程)
【6月更文挑战第16天】本文介绍了TestNG中`@DataProvider`的两种使用方法。本文通过实例展示了TestNG如何利用`@DataProvider`结合方法名和`ITestContext`来灵活地为测试方法传递参数。
9 1
|
3天前
|
XML 存储 测试技术
《手把手教你》系列基础篇(七十四)-java+ selenium自动化测试-框架设计基础-TestNG实现DDT - 上篇(详解教程)
【6月更文挑战第15天】本文介绍了TestNG的数据驱动测试(Data Driven Testing, DDT)概念和好处,并提供了两个实战示例。数据驱动测试允许使用不同的测试数据执行相同的测试用例,这些数据可以从外部文件或数据库获取。这种方法提高了测试效率,减少了冗余代码,并便于应对应用程序变更。
15 0
|
5天前
|
Web App开发 XML 安全
《手把手教你》系列基础篇(七十三)-java+ selenium自动化测试-框架设计基础-TestNG实现启动不同浏览器(详解教程)
【6月更文挑战第14天】本文介绍了如何使用TestNg进行自动化测试,特别是通过变量参数启动不同浏览器的步骤。
15 5
|
6天前
|
监控 Java 测试技术
《手把手教你》系列基础篇(七十二)-java+ selenium自动化测试-框架设计基础-TestNG简单介绍(详解教程)
【6月更文挑战第13天】本文介绍了TestNG单元测试框架,它是一个灵感来源于JUnit和NUnit的测试框架,支持多种级别的测试,如单元测试、集成测试等。TestNG的特点包括丰富的注解、数据驱动测试、变量支持、自动生成HTML测试报告等。与JUnit和NUnit相比,TestNG在某些功能上更为强大。文章还详细讲解了如何在Eclipse中安装TestNG插件,提供了在线安装、更新站点安装和离线安装三种方法,并展示了安装成功的验证步骤。最后,通过一个项目实战案例展示了如何使用TestNG编写和运行测试代码。
14 2
|
6天前
|
Java 大数据 API
【大数据】HDFS、HBase操作教程(含指令和JAVA API)
【大数据】HDFS、HBase操作教程(含指令和JAVA API)
38 0
【大数据】HDFS、HBase操作教程(含指令和JAVA API)
|
7天前
|
JavaScript Java 测试技术
《手把手教你》系列技巧篇(七十一)-java+ selenium自动化测试-自定义类解决元素同步问题(详解教程)
【6月更文挑战第12天】本文介绍了如何创建一个自定义类库来解决自动化测试中的元素同步问题。作者指出,大部分错误源于元素因时间不同步而引发,为此提供了一种解决方案。在项目实践中,首先在`library`包下创建名为`MyWait`的类,包含一个方法`isElementPresent`,该方法通过循环尝试并等待指定元素出现,避免了直接使用时间等待可能导致的不准确性。之后,在测试类中调用此自定义方法,成功实现了元素同步。代码示例展示了如何在Java+Selenium自动化测试中应用这个自定义类。
27 2
|
8天前
|
XML Web App开发 Java
《手把手教你》系列技巧篇(七十)-java+ selenium自动化测试-Java中如何读取properties配置文件内容(详解教程)
【6月更文挑战第11天】本文介绍了Java自动化测试中读取properties配置文件的方法。文章首先说明了为何要将配置参数放在properties文件中,然后简述了properties文件的作用和常用的读取方式,包括通过`java.util.Properties`类和`java.util.ResourceBundle`类。接着详细列举了`Properties`类的主要方法,如`getProperty()`、`load()`、`setProperty()`和`store()`等。
14 1