java - 如果 MANIFEST.MF 不存在,主类的定义是什么
问题描述
在 Eclipse 中导出到 JAR 时有两个选项:导出为可运行的 JAR 和导出为 JAR。
我知道可运行的 jar 包含一个 MANIFEST.MF 文件,该文件定义了执行 jar 时要执行的 Main 类。
我也知道不可运行的 jar 只是类库,可以添加到类路径中以便重用代码。它包含一个清单文件,但其中没有定义的主类。
如果未定义主类,如何执行不可运行的 JAR 文件?拥有一个定义主类的 MANIFEST.MF 文件的优点/缺点是什么?一个比另一个更稳定吗?
解决方案
如果 MANIFEST.MF 不存在,主类的定义是什么
如果 JAR 文件没有“META-INF/MANIFEST.MF”组件,则它不是 JAR 文件。它只是一个 ZIP 文件,不能java -jar ...
与 ZIP 文件一起使用。(您可以在类路径中包含一个 ZIP 文件,但通常不会这样做。)
如果一个 JAR 文件有一个没有Main-Class
属性的 MANIFEST.MF,那么它就不是一个可执行的JAR 文件,并且java -jar ...
会失败。
但是(如前所述)许多 JAR 文件是库而不是应用程序。对他们来说,入口点类没有任何意义。
如果未定义主类,如何执行不可运行的 JAR 文件?
(首选的 Java 术语是“可执行的”而不是“可运行的”。)
那样的话,java -jar ...
就会失败。相反,您可以像这样运行应用程序:
java -cp <classpath> <other-options> com.example.MyApp.Main <args>
其中com.example.MyApp.Main
是一个主/入口点类,<classpath>
包括 JAR(或 ZIP)文件和任何其他运行时依赖项。
请注意,一个应用程序 JAR 文件可能包含多个入口点类,用户可以决定使用哪一个。
拥有一个定义主类的 MANIFEST.MF 文件的优点/缺点是什么?
首先,如果您使用该jar
命令创建一个 JAR 文件,那么它将有一个 MANIFEST.MF。该命令不会创建没有 JAR 的 JAR。
此外,您还可以在 MANIFEST.MF 中包含其他有用的内容。其中包括数字哈希(用于签名的 JAR)和一个Class-Path
在 JAR 启动时使用的属性-jar
。有关更多详细信息,请参阅JAR 文件规范。
在 JAR 文件中包含属性的优点是:Main-Class
- 如果您想使用
-jar
. - 这意味着用户不需要知道(或键入)入口点类的全名。
拥有一个Main-Class
属性没有明显的缺点。如果用户不使用java -jar ...
启动方法,则任何此类属性都将被忽略。但我想你可能会说在库Main-Class
JAR上放置一个无意义的属性可能会导致天真的用户得到一个误导性错误。这是毛骨悚然...
一个比另一个更稳定吗?
不是直接的。
您可能会争辩说using -jar
更稳定,因为可执行 JAR 会忽略命令行上的CLASSPATH
环境变量和参数。-cp
但另一方面是您不能强制用户使用-jar
(或双击)来启动命令。您可以通过提供一个 shell 脚本或 BAT 文件来使用适当的入口点类名和适当的类路径来启动应用程序,从而获得类似的稳定性。
我在没有类路径或项目文件的情况下在 Eclipse 中执行了一个不可运行的 jar,然后我运行它并且它工作了。它能够识别主类并从那里运行它。我的问题是:它是如何识别它的?
好的......这是一个不同的问题。
这里实际发生的是 Eclipse 项目有一堆配置信息,其中包括构建依赖项。这些为 Eclipse 启动器提供了一个默认的类路径。然后,当您在run
没有现有运行配置的情况下使用 Eclipse 的命令时,Eclipse 将搜索当前项目中的所有类,以查找任何具有public static void main(String[])
方法的类。如果它只找到一个这样的类,它假定它是入口点类,并为项目/类创建一个运行配置。启动该配置时,Eclipse 会执行java -cp <classpath> <class-name> <args>
.
笔记:
这是Eclipse 特定的行为。标准的 Java 工具链不会做这样的事情。
此处未使用 Eclipse
java -jar
,因此不会查询清单来查找入口点类。众所周知,这会破裂。例如,我听说如果您删除主类并创建一个新类,则启动配置不会更新,并且当您尝试“运行”它时会出现 JVM 启动错误。
推荐阅读
- javascript - 如果 ref.current 的子元素发生变化,如何更新反应 ref?
- python-3.x - Flask App 部署到 Heroku 时出错 at=error code=H10 desc="App crashed" method=GET path="/"
- python - 布尔二维数组的子区域
- reactjs - 抛出错误时,如何读取错误数据
- sql - 如何使用 SELECT 子句中使用的非聚合列而不在 GROUP BY 子句中使用它?
- python - 根据条件在一个数据帧中拆分和替换熊猫中的另一个数据帧
- javascript - 尝试将 Json 迭代到 Javascript 数组中,然后输入到 Treant js 图表中
- c++ - 如何在 C++ 中从子类中封装用户函数
- vue.js - 如何在单个库中预编译多个 vue 文件并使其易于导入?
- php - 如何打破 PHP 面包屑循环?