【问题标题】:NoClassDefFoundError after creating executable jar with libraries using ant使用 ant 创建带有库的可执行 jar 后出现 NoClassDefFoundError
【发布时间】:2018-06-09 00:34:54
【问题描述】:

我创建了一个示例应用程序来演示我面临的问题。 我的示例应用程序包含带有 main 方法的单个类和对 log4j 的依赖

package com.example.foo;

public class MainClass {
    private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(MainClass.class);

    public static void main(String[] args) {
        LOG.info("Hello Ant Build");
    }
}

我在我的 lib 文件夹中添加了两个 jar 文件 slf4j-api-1.7.25.jarslf4j-simple-1.7.25.jar

接下来,我创建了一个 ant 脚本来构建这个项目。 (这个项目在eclipse下运行成功,但这不是我需要的)

我的 build.xml 是

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project name="sample-app" basedir="../SampleApp" default="jar">
    <property name="source.dir" value="src"/>
    <property name="lib.dir" value="lib"/>
    <property name="class.dir" value="bin"/>
    <property name="jar.dir" value="dist"/>
    <property name="jar.file" value="${jar.dir}/${ant.project.name}.jar"/>
    <property name="main-class" value="com.example.foo.MainClass"/>

    <path id="libraries.path">    
        <fileset dir="${lib.dir}">
            <include name="*.jar"/>
        </fileset>
    </path>

    <target name="clean" description="delete old files">
        <delete dir="${class.dir}"/>
        <delete dir="${jar.dir}"/>
    </target>

    <target name="compile" description="build class files" depends="clean">
        <mkdir dir="${class.dir}"/>
        <javac srcdir="${source.dir}" destdir="${class.dir}" includeantruntime="false">
            <classpath refid="libraries.path"/>
        </javac>
    </target>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <mkdir dir="${class.dir}/${lib.dir}"/>
        <copy todir="${class.dir}/${lib.dir}" flatten="true">
            <path refid="libraries.path"/>
        </copy>

        <manifestclasspath property="manifest.classpath" jarfile="${jar.file}">
            <classpath refid="libraries.path"/>
        </manifestclasspath>

        <jar destfile="${jar.file}" basedir="${class.dir}">
            <manifest>
                <attribute name="Main-Class" value="${main-class}"/>
                <attribute name="Class-Path" value="${manifest.classpath}"/>
            </manifest>
        </jar>  
    </target>
</project>

这将成功创建 jar 文件。 jar 文件中存在所有必需的类文件和 jar 文件。

但是当我使用 java -jar sample-app.jar 执行 jar 时,我得到了 NoClassDefFoundError

$ java -jar sample-app.jar
java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
        at com.example.foo.MainClass.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 1 more
Exception in thread "main"

MANIFEST.MF文件的内容是:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.10.1
Created-By: 1.8.0_111-b14 (Oracle Corporation)
Main-Class: com.example.foo.MainClass
Class-Path: ../lib/slf4j-api-1.7.25.jar ../lib/slf4j-simple-1.7.25.jar

我无法找出 jar 文件中的错误或缺失。请帮助我找出我的 ant 脚本的问题。提前致谢。

【问题讨论】:

    标签: java jar ant build-script antbuilder


    【解决方案1】:

    标准类加载器不会从您的 jar 中加载 jar 文件(请参阅https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html)。

    使用 MANIFEST.MF 中给定的 Class-Path 条目,需要将这些 jar 文件放置到文件夹“../lib”,即执行可执行 jar 目录的父文件夹中的“lib”文件夹。

    其他解决方案是:

    1. 编写自定义类加载器
    2. 提取 slf4j jar 并重新打包内容

    我不会推荐其中任何一个。

    【讨论】:

    • 是的.. 我可以看到评论 - "To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes"。知道应该使用什么代码来加载它们吗?
    • 正如我所说,为此编写自定义类加载器并不是一个好的解决方案。无需任何代码更改,您只需将外部 jar 文件保存在“../lib”文件夹中(或者编辑 ant 脚本,使 Class-Path 条目指向 ./lib 并将 jar 保存在那里)。 jar 位于类路径中(由清单中的 Class-Path 指定),但不在 jar 内部。
    • 另见关于该问题的旧帖子:stackoverflow.com/questions/183292/…
    猜你喜欢
    • 2011-05-29
    • 2014-08-30
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2020-09-28
    • 2015-01-13
    • 2010-11-15
    • 1970-01-01
    相关资源
    最近更新 更多