68

我有一个应用程序,我正试图将其包装到一个 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 或打包 jar 的工具),第三方解决方案可能已经出现。最终目标是创建一个 jar,它可以从我的开发 Windows 机器复制到 Linux 服务器(带有任何依赖的 jar)并用于填充数据库(因此类路径可能最终在开发和部署环境之间有所不同)。任何有关此谜团的线索将不胜感激!

4

6 回答 6

63

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

-罐

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

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

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

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

-Xbootclasspath/a:路径

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

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

于 2008-10-30T13:29:27.740 回答
37

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

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

于 2012-01-12T16:18:34.667 回答
20

这是正在发生的问题,

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

解决方案:-

  1. 右键单击项目,选择导出。
  2. 选择 Java 文件夹并在其中选择 Runnable JAR File 而不是 JAR 文件。
  3. 选择适当的选项并在库处理部分选择第三个选项,即(将所需的库复制到生成的 JAR 旁边的子文件夹中)。

[ EDIT = 3rd 选项除了 jar 之外还生成一个文件夹,2nd 选项(“将所需的库打包到生成的 JAR”)也可以在您拥有 jar 时使用。]

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

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

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

于 2012-09-05T13:46:51.510 回答
3

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

我更喜欢使用OneJar来解决这个问题。

于 2008-10-30T14:11:28.997 回答
3

我的罐子也有同样的问题

  1. 创建 MANIFEST.MF 文件:

清单版本:1.0

密封:真实

类路径:. lib/jarX1.jar lib/jarX2.jar lib/jarX3.jar

主类:com.MainClass

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

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

  1. 选择使用工作区中的现有清单并选择 MANIFEST.MF 文件

这对我有用:)

于 2015-11-19T10:16:17.473 回答
0

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

于 2012-01-12T21:55:36.537 回答