Java Jar 文件主类从命令行运行时运行,而不是从 Windows 批处理文件运行

Posted

技术标签:

【中文标题】Java Jar 文件主类从命令行运行时运行,而不是从 Windows 批处理文件运行【英文标题】:Java Jar file main class run when runs from command line, but not from Windows batch file 【发布时间】:2021-10-01 05:13:49 【问题描述】:

我正在重新使用一个独立的基于 Swing 的 Java 类来备份和恢复 mysql 数据库。

我已经在我的开发系统上测试了从 Windows 批处理文件 (.bat) 运行它,它在那里工作。

但是,如果我在不同的 Windows 上运行批处理文件,我会收到“找不到主类”异常。

但是,当我直接在命令行上运行命令时,它可以工作。

批处理文件中运行它的命令是:

java -cp lda-services.jar;bip-services-1.6.0.0-SNAPSHOT.jar;decryptor-1.6.0.0-SNAPSHOT.jar;slf4j-api-1.7.31.jar;commons-io-2.6.jar com.ilcore.util.SosaMaintenanceJFrame

SosaMaintenanceJFrame 类包含在 lda-services jar 中。

这是错误信息:

Error: Could not find or load main class com.ilcore.util.SosaMaintenanceJFrame
Caused by: java.lang.ClassNotFoundException: com.ilcore.util.SosaMaintenanceJFrame

该类肯定在 jar 文件中,因为我已经将它提取到文件中并查看了它。

对为什么会发生这种情况有任何想法吗?我需要在一个批处理文件中运行,这样用户就可以点击它来运行它。

【问题讨论】:

【参考方案1】:

最可能的解释

您的路径是相对的,这意味着除非您从正确的位置运行批处理文件,否则它将无法工作。一般来说,有一个批处理文件,上面钉有一个不可见的骑手:“如果不从适当的目录运行,我会以神秘的方式破坏”是一个糟糕的批处理文件 - 让它变得更好。

更好的解决方案

或者,更好的是,摆脱它。您不需要批处理文件来分发 java 程序。

分发java程序的正确方法:

现代的做法与您在这里的情况非常不同:JRE 已经死了,您必须发布一个安装程序来完成整个工作,特别是包括一个 java 运行时(不再称为 JRE,您可以发布并跟上它)迄今为止,如果相关)。对于您在这里所做的事情而言,这可能是一座太远的桥梁。相关工具包括 jlink。

稍微不那么现代的镜头涉及带有清单的罐子:

您的 jar 文件应该包含一个清单。此清单必须包含 2 个相关条目:

Class-Path: lda-services.jar bip-services-1.6.0.0-SNAPSHOT.jar decryptor-1.6.0.0-SNAPSHOT.jar slf4j-api-1.7.31.jar commons-io-2.6.jar

Main-Class: com.ilcore.util.SosaMaintenanceJFrame

您可以使用jar-m 开关,或者只包含清单(它只是jar 中的一个文件):它位于META_INF/MANIFEST.MF,它是一个文本文件,每一行都是一个条目,一个条目由 key: value 对组成。

当一个 jar 包含此内容时,只需双击该 jar 并运行 java -jar thejar.jar 即可完成所有工作:Java 将加载指定的 jar 作为类路径的一部分,并且至关重要的是,这些 jar 被解析为路径 相对于 jar 所在的目录,因此当您尝试从其他地方启动它们时它确实有效,即如果您这样做:

C:
CD \
java -jar "c:\Program Files\MyApp\myapp.jar"

它工作正常,而该批处理脚本会由于位置错误而失败。

构建系统也允许您定义清单,查看构建系统文档以了解如何执行此操作,这很容易,而且如果您在网上搜索大量教程,例如'manifest executable jar maven' 之类的。

您可以考虑制作一个带阴影的罐子。但我不会。

一个带阴影的 jar 获取所有依赖项并将它们打包到您的主 jar 中,因此只有一个 jar。现在不需要 Class-Path 条目(您运行的 jar 显然已经在类路径中,并且没有其他要包含的内容)并且您的应用作为“只是”一个 jar 文件提供。

但这主要是一条红鲱鱼:不再有消费者 JRE,因此您已将用户体验从 D- 变为 D。如果您真的关心为您的用户提供良好的体验,那么就无法绕过某种安装过程,一旦有了它,拥有单独的 jar 就不再是问题。当涉及到签名的 jar 时,单独的 jar 不那么毛茸茸,更容易保持最新状态,并且周转速度明显更快(当你构建你的东西​​并想要运送你构建的东西时,阴影需要很长时间,所以最好剪掉它走出去)。您的 CI 系统越快告诉您失败的测试越好。

在中间相遇

您不必升级到模块等。你可以做的是使用类似launch4j 的东西。目的是最终得到一个 zip 文件以及安装说明:在某处创建一个目录。把这个拉链解压进去。双击“myapp.exe”。完成。

该 zip 将包含一个完整的 JRE、您的所有 jar 文件 deps 和您的主应用程序,以及一个 launch4j 为您制作的 exe 文件,该文件使用打包到 jar 中的 JRE 启动您的应用程序。这意味着您确切知道正在使用哪个 JRE,它甚至可以在尚未安装的系统上工作(这些天,应该是所有这些 - '最终用户从 oracle 下载 JRE 的概念并且用户 + 预言机一起工作以保持该东西是最新的并且没有安全问题',已经死了)。

它是一个 EXE 的事实很好:现在如果用户例如alt+tabs 通过他们的应用程序,他们会得到你的应用程序,带有你的名字和你的图标,而不是带有丑陋咖啡杯标志的“javaw.exe”。

【讨论】:

感谢您的详细回答。问题是我以管理员身份运行它,这显然使它认为 jar 文件不在同一个目录中,如果你不以管理员身份运行它。 我得到了主路径和类路径,谢谢。但是由于某种原因,当我以管理员身份运行运行 jar 文件的批处理文件时,它不起作用,在这种情况下说找不到 lda-services jar。双击不起作用,顺便说一句。解决方法是以管理员身份从命令行运行它,但如果没有它,它会很好。 好的,问题是当您切换到管理员时,它会更改您的目录。所以我只需要 cd 回到原来的目录。【参考方案2】:

但是,当我尝试从 Maven 生成的 jar 文件中运行它时,却出现“找不到类”异常。

即使您没有收到该错误,除非您使用 Maven Shade,否则您会收到另一个错误,因为这是您使用单个 jar 运行该错误的唯一方法。我对为什么会发生 特定 错误的猜测是,您尝试运行的应用程序类实际上位于 *SNAPSHOT* jars 之一中

【讨论】:

我更新了帖子,使其更加准确并提供了新信息;如果我直接从命令行运行该命令,而不是从批处理文件运行,该命令实际上可以工作。我在类路径中指定依赖的 jar。 请发布jar tf lda-services.jar | find "SosaMaintenanceJFrame" 的输出 请记住,批处理文件不可重定位。仅当当前目录恰好是其中包含这些 jar 的目录时,它才会起作用。 See

以上是关于Java Jar 文件主类从命令行运行时运行,而不是从 Windows 批处理文件运行的主要内容,如果未能解决你的问题,请参考以下文章

java运行时找不到主类

运行java文件显示找不到或无法加载主类怎么解决?

java故障处理基础命令行工具

运行 java -jar 时包含外部 jar

命令行java -classpath 的使用

运行jar文件时Java找不到主类[重复]