尝试使用java.exe -jar运行我的jar时出现NoClassDefFoundError ...出了什么问题?

时间:2008-10-30 13:26:54

标签: java jar classpath executable-jar

我有一个应用程序,我正在尝试将其包装到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类。最后,我的jar的内容显示:

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或包装罐子的工具),第三方解决方案可能已经解决了。最终目标是创建一个可以从我的开发Windows框复制到Linux服务器(带有任何依赖的jar)的jar,并用于填充数据库(因此类路径可能会在开发和部署环境之间变得不同)。任何关于这个谜团的线索都将非常感激!

6 个答案:

答案 0 :(得分:56)

-jar选项与-classpath互斥。查看旧说明here

  

-jar

     

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

     

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

     

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

快速而肮脏的黑客是将类路径附加到引导类路径:

  

-Xbootclasspath / A:<强> 路径

     

指定以冒号分隔的directires,JAR存档和ZIP存档路径,以附加到默认引导程序类路径。

然而,正如@Dan正确地说,正确的解决方案是确保您的JAR清单包含所需的所有JAR的类路径。

答案 1 :(得分:28)

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

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

答案 2 :(得分:17)

这是正在发生的问题,

如果JAR文件是从“C:\ java \ apps \ appli.jar”加载的,并且您的清单文件具有Class-Path:引用“lib / other.jar”,则类加载器将查找“C” :\ java \ apps \ lib \“for”other.jar“。它不会查看JAR文件条目“lib / other.jar”。

<强>解决方案: -

  1. 右键单击项目,选择导出。
  2. 选择Java文件夹,然后在其中选择Runnable JAR File而不是JAR文件。
  3. 选择正确的选项,然后在“库处理”部分中选择第3个选项,即(将所需的库复制到生成的JAR旁边的子文件夹中)。
  4. [ EDIT =第3个选项除了jar之外还会生成一个文件夹,第二个选项(“将所需的包打包到生成的JAR中”)也可以用作jar。 ]

    1. 单击“完成”,将在指定位置创建JAR以及包含清单文件中提到的JARS的文件夹。
    2. 打开终端,为你的jar提供正确的路径并使用此命令运行它java -jar abc.jar

      现在将发生的事情是类加载器将在引用的JARS的正确文件夹中查找,因为现在它们存在于包含您的应用程序JAR的同一文件夹中。现在没有抛出“java.lang.NoClassDefFoundError”异常

    3. 这对我有用......希望它对你有用!!!

答案 3 :(得分:4)

如果您在程序中使用外部库并且尝试将所有内容打包在一个jar文件中,那就不是那么简单,因为类路径问题等。

我更倾向于使用OneJar来解决这个问题。

答案 4 :(得分:2)

我的罐子也有同样的问题 解决方案

  1. 创建MANIFEST.MF文件:
  2.   

    清单 - 版本:1.0

         

    密封:真实

         

    Class-Path :. lib / jarX1.jar lib / jarX2.jar lib / jarX3.jar

         

    Main-Class:com.MainClass

    1. 右键单击项目,选择导出。
    2.   

      选择导出已检查项目的所有输出文件夹

      1. 选择使用工作区中的现有清单并选择MANIFEST.MF文件
      2. 这对我有用:)

答案 5 :(得分:0)

我发现当我使用清单时,类路径的jar列表需要在列出每个jar之后有空格,例如“required_lib / sun / pop3.jar required_lib / sun / smtp.jar”。即使它是列表中的最后一个。