NoClassDefFoundError,同时尝试用java运行我的jar.exe -jar...怎么了?

2022-08-31 14:21:33

我有一个应用程序,我正在尝试将其包装到jar中以便于部署。当应用程序作为一组可从 CLASSPATH 访问的类运行时,应用程序编译并运行良好(在 Windows cmd 窗口中)。但是当我把我的类加起来,并尝试在同一个cmd窗口中用java 1.6运行它时,我开始得到异常:

C:\dev\myapp\src\common\datagen>C:/apps/jdk1.6.0_07/bin/java.exe -classpath C:\myapp\libs\commons -logging-1.1.jar -server -jar DataGen.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
    at com.example.myapp.fomc.common.datagen.DataGenerationTest.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
    ... 1 more

有趣的是,令人反感的LogFactory似乎在commons-logging-1.1.jar中,它在指定的类路径中。jar文件(是的,它真的在那里):

C:\dev\myapp\src\common\datagen>dir C:\myapp\libs\commons-logging-1.1.jar
 Volume in drive C is Local Disk
 Volume Serial Number is ECCD-A6A7

 Directory of C:\myapp\libs

12/11/2007  11:46 AM            52,915 commons-logging-1.1.jar
           1 File(s)         52,915 bytes
           0 Dir(s)  10,956,947,456 bytes free

commons-logging-1.1.jar文件的内容:

C:\dev\myapp\src\common\datagen>jar -tf C:\myapp\libs\commons-logging-1.1.jar
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/commons/
org/apache/commons/logging/
org/apache/commons/logging/impl/
META-INF/LICENSE.txt
META-INF/NOTICE.txt
org/apache/commons/logging/Log.class
org/apache/commons/logging/LogConfigurationException.class
org/apache/commons/logging/LogFactory$1.class
org/apache/commons/logging/LogFactory$2.class
org/apache/commons/logging/LogFactory$3.class
org/apache/commons/logging/LogFactory$4.class
org/apache/commons/logging/LogFactory$5.class
org/apache/commons/logging/LogFactory.class
... (more classes in commons-logging-1.1 ...)

是的,commons-logging有LogFactory类。最后,我的罐子清单的内容:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 10.0-b23 (Sun Microsystems Inc.)
Main-Class: com.example.myapp.fomc.common.datagen.DataGenerationTest
Class-Path: commons-logging-1.1.jar commons-lang.jar antlr.jar toplink
 .jar GroboTestingJUnit-1.2.1-core.jar junit.jar

这让我和任何同事都陷入了困境,我已经烦扰了一天多了。只是为了挑选答案,至少就目前而言,由于许可限制和公司政策(例如:用于创建exe或打包jar的工具),第三方解决方案可能已经出局。最终目标是创建一个jar,它可以从我的开发Windows盒复制到Linux服务器(带有任何依赖的jar)并用于填充数据库(因此类路径最终可能会在开发和部署环境之间有所不同)。任何关于这个谜团的线索将不胜感激!


答案 1

-jar 选项与 -classpath 互斥。在此处查看旧描述

-罐

执行封装在 JAR 文件中的程序。第一个参数是 JAR 文件的名称,而不是启动类名称。为了使此选项正常工作,JAR 文件的清单必须包含一行,其形式为 Main-Class: classname。在这里,classname 标识具有公共静态 void main(String[] args) 方法的类,该方法用作应用程序的起点。

有关使用 Jar 文件和 Jar 文件清单的信息,请参阅 Jar 工具参考页和 Java 教程的 Jar 跟踪。

使用此选项时,JAR 文件是所有用户类的源,而其他用户类路径设置将被忽略。

一个快速而肮脏的技巧是将你的类路径附加到引导类路径:

-Xbootclasspath/a:path

指定要追加到缺省引导类路径的以冒号分隔的指导路径、JAR 存档和 ZIP 存档。

但是,正如@Dan正确指出的那样,正确的解决方案是确保您的JAR清单包含它将需要的所有JAR的类路径。


答案 2

您可以省略该选项并启动jar文件,如下所示:-jar

java -cp MyJar.jar;C:\externalJars\* mainpackage.MyMainClass


推荐