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



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

C:devmyappsrccommondatagen>C:/apps/jdk1.6.0_07/bin/java.exe -classpath C:myapplibscommons -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似乎是公共的-logging-1.1.jar,它在指定的类路径中。jar文件(是的,它确实在那里):

C:devmyappsrccommondatagen>dir C:myapplibscommons-logging-1.1.jar
 Volume in drive C is Local Disk
 Volume Serial Number is ECCD-A6A7
 Directory of C:myapplibs
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:devmyappsrccommondatagen>jar -tf C:myapplibscommons-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日志有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),并用于填充数据库(因此,开发环境和部署环境之间的类路径可能会有所不同)。任何关于这个谜团的线索都将不胜感激!

.jar选项与-classpath互斥。请参阅此处的旧描述

-罐子

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

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

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

一个快速而肮脏的破解方法是将类路径附加到引导类路径:

-Xbootclasspath/a:路径

指定一个以冒号分隔的目录、JAR档案和ZIP档案路径,以附加到默认的引导类路径。

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

您可以省略-jar选项,并像这样启动jar文件:

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

这就是正在发生的问题,

如果JAR文件是从"C:\java\apps\appli.JAR"加载的,并且您的清单文件具有类路径:引用"lib/other.JAR",则类加载器将在"C:\java\apps\lib\"中查找"other.JAR"。它不会查找JAR文件条目"lib/other.JAR"。

解决方案:-

  1. 在项目上单击鼠标右键,选择"导出"
  2. 选择Java文件夹,然后在其中选择可运行的JAR文件而不是JAR文件
  3. 选择适当的选项,然后在库处理部分选择第三个选项,即(将所需库复制到生成的JAR旁边的子文件夹中)

[EDIT=除了jar之外,第三个选项还可以生成一个文件夹,第二个选项("将所需库打包到生成的jar中")也可以在拥有jar时使用。]

  1. 单击finish,将在指定位置创建JAR,同时创建一个文件夹,该文件夹包含清单文件中提到的JARS
  2. 打开终端,为您的jar提供正确的路径,并使用以下命令运行它java-jarabc.jar

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

这对我有效…希望它对你也有效!!!

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

对于这个问题,我更喜欢使用OneJar。

我的jar也有同样的问题溶液

  1. 创建MANIFEST.MF文件:

清单版本:1.0

密封:真正的

类路径:。lib/jarX1.jar lib/jarX2.jar lib/jar X3.jar

主要类别:com.MainClass

  1. 在项目上单击鼠标右键,选择"导出"

选择导出选中项目的所有输出文件夹

  1. 从工作区中选择"使用现有清单",然后选择manifest.MF文件

这对我来说很有效:)

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

在g_tom的解决方案上进行扩展后,我发现有一个用于运行jar文件的批处理文件更容易。

:: To run MyClass.jar, name this file MyClass.bat and place it 
:: in the same directory as MyClass.jar and any dependent jars
@echo off 
setlocal enableextensions
setlocal enabledelayedexpansion
set BAT_FILE=%~n0
cd %~dp0
java -cp "!BAT_FILE:.bat=!.jar;.*" !BAT_FILE:.bat=! %*

最新更新