Java Jar 文件主要 class 运行 当 运行s 来自命令行,而不是来自 Windows 批处理文件

Java Jar file main class run when runs from command line, but not from Windows batch file

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

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

但是,如果我 运行 将批处理文件放在另一个 Windows 上,我会收到“未找到主要 class”异常。

但是,当我直接在命令行上运行命令时,它起作用了。

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

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 class 包含在 lda-services jar 中。

错误信息如下:

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

class肯定在jar文件里,我已经解压出来看到了

想知道为什么会这样吗?我需要在批处理文件中 运行 以便用户只需单击它即可 运行 它。

But when I try running it from the jar file generated by Maven, however, I get a "class not found" exception.

即使您没有遇到该错误,除非您使用 Maven Shade,否则您也会遇到另一个错误,因为这是您要 运行 使用单个 jar 的唯一方法。我对为什么会出现 特定 错误的猜测是,您尝试 运行 的应用程序 class 实际上位于 *SNAPSHOT* 罐子中

最有可能的解释

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

更好的解决方案

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

分发java程序的正确方法:

  • 现代的做法与你这里的非常不同:JRE 已经死了,你必须发布一个安装程序来完成所有事情,特别是包括 java 运行time(不再称为 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,然后 运行ning java -jar thejar.jar 将处理所有事情:Java 将加载指定的 jar 作为类路径,而这些,至关重要的是,被解析为相对于 jar 所在目录的路径 ,因此当您尝试从其他地方启动它们时它确实有效,即如果您这样做:

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

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

构建系统也可以让您定义清单,查看您的构建系统文档以了解如何执行此操作,这很容易,如果您在网上搜索例如'manifest executable jar maven' 或诸如此类的东西。

  • 你可以考虑做一个有阴影的罐子。但是我不会。

一个阴影 jar 将你所有的依赖项打包到你的主 jar 中,这样就只有一个 jar。现在不需要 Class-Path 条目(您 运行 的 jar 显然已经在类路径中并且没有其他内容可以包含)并且您的应用程序作为 'just' 单个 jar 文件提供.

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

  • 中间相遇

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

zip 将包含整个 JRE、所有 jar 文件 dep、主应用程序和 launch4j 为您制作的 exe 文件,它使用打包到 jar 中的 JRE 启动您的应用程序。这意味着您确切地知道正在使用哪个 JRE,它甚至可以在尚未安装的系统上运行(这些天,应该是所有这些 - 'end user downloads a JRE from oracle and the user + oracle work together to keep that thing up to date and security-issue-free' 的概念已经过时).

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