由于:java.lang.NoClassDefFoundError: org/apache/log4j/Logger引起的问题

73

我遇到了一个有趣的问题,即在运行时找不到org.apache.log4j.Logger类。 我正在尝试进行授权,但失败了:

OAuthAuthorizer oauthAuthorizer = new OAuthAuthorizer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, SAML_PROVIDER_ID, userId);

我正在使用JDeveloper 11.1.1.6。以下是我知道的情况:

  1. 我查看了UI.war / WEB-INF / lib目录,发现log4j-1.2.17.jar在那里。

  2. complaining about it的类是org.opensaml.xml.XMLConfigurator

Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Logger
    at org.opensaml.xml.XMLConfigurator.<clinit>(XMLConfigurator.java:60)
    at org.opensaml.DefaultBootstrap.initializeXMLTooling(DefaultBootstrap.java:195)
    at org.opensaml.DefaultBootstrap.bootstrap(DefaultBootstrap.java:91)
    at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.getSAMLBuilder(SAML2AssertionGenerator.java:156)
    at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.createSubject(SAML2AssertionGenerator.java:187)
    at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.buildAssertion(SAML2AssertionGenerator.java:114)
    at com.intuit.ipp.aggcat.util.SAML2AssertionGenerator.generateSignedAssertion(SAML2AssertionGenerator.java:83)
    at com.intuit.ipp.aggcat.util.SamlUtil.createSignedSAMLPayload(SamlUtil.java:156)
    at com.intuit.ipp.aggcat.util.OAuthUtil.getOAuthTokens(OAuthUtil.java:60)
    at com.intuit.ipp.aggcat.core.OAuthAuthorizer.<init>(OAuthAuthorizer.java:85)
    at com.incomemax.view.intuit.WebUtil.getAggCatService(WebUtil.java:91)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
    ... 64 more
  • 我反编译了XMLConfigurator,奇怪的是它没有导入org.apache.log4j.Logger,而是使用了也在我的jar目录中的org.slf4j.Logger(slf4j-api-1.7.5.jar)。有趣的是,我的反编译中第60行(请参见堆栈跟踪)是一行空行。

  • 当然,如果我在设计时添加Logger.xxxxx,它就能找到。

  • 我正在直接使用示例Java代码中的代码/ jar,但导入到我的现有应用程序中。

  • 我一直在网上搜索答案,我相信我已经检查了我能想到的所有领域。我还参考了这个非常好的页面:http://myarch.com/classnotfound/

    给定授权是使用Intuit开发者API的第一步,我有点卡住了。

    根据@jhadesdev建议的输出进行添加:

    所有版本的log4j Logger:

    • zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class

    从OAuthAuthorizer类的类加载器可见的所有log4j版本:

    • zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class

    所有版本的XMLConfigurator:

    • jar:file:/C:/Oracle/Middleware11116/modules/com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class

    • zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class

    • zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class

    从OAuthAuthorizer类的类加载器可见的所有XMLConfigurator版本:

    • jar:file:/C:/Oracle/Middleware11116/modules/com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class

    • zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class

    • zip:C:/Users/Chris/AppData/Roaming/JDeveloper/system11.1.1.6.38.61.92/DefaultDomain/servers/DefaultServer/tmp/_WL_user/j2ee-app/lt5l71/war/WEB-INF/lib/xmltooling-1.3.


    如果您正在使用Tomcat 8并且已经为您的Web应用程序中的任何文件夹创建了符号链接,则需要在$CATALINA_HOME/conf/context.xml中添加一个allowLinking属性:<Context><Resources allowLinking="true"/> - GlenPeterson
    11个回答

    50

    在运行时,您的应用程序无法找到该jar文件。

    引用自此答案,作者为Jared

    这种情况下,我们在脑海中区分两个不同的异常非常重要:
    1. java.lang.ClassNotFoundException 是一个异常,它表示类没有在 classpath 上找到。这意味着我们试图加载类定义,但是类在 classpath 上不存在。
    2. java.lang.NoClassDefFoundError 是一个错误,它表示 JVM 在其内部类定义数据结构中查找类的定义时未找到它。这与无法从 classpath 加载它不同。通常,这表示我们之前尝试从 classpath 加载类,但由于某些原因而失败 - 现在我们正在再次尝试,但我们甚至不会尝试加载它,因为我们之前加载它失败了。之前的失败可能是 ClassNotFoundException 或 ExceptionInInitializerError(表示静态初始化块中的故障)或任何其他问题。关键是,NoClassDefFoundError 不一定是 classpath 的问题。

    相似之处和差异之处


    非常感谢您的解释,@premraj。基于此,我在代码开头添加了LOG.error("Just entered getAggCatService");并确保我的导入是org.apache.log4j.Logger。我的日志消息被显示出来了。这是否意味着org.apache.log4j.Logger已被加载并找到? - lovebeer84
    这就是当一个人变得极度懒惰并且使用模糊的类名时会发生的事情。Java程序员干得好。 - Boss Man

    25

    您可以在pom文件中使用以下Maven依赖项。否则,您可以从网络下载以下两个jar文件并将其添加到构建路径中。

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.4</version>
    </dependency>
    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.6.4</version>
    </dependency>
    

    这段内容来自我的工作项目。首先请确保它在你的项目中可以正常工作。然后你可以更改版本以使用任何其他(兼容的)jar包。

    对于AggCat,你可以参考示例java应用程序的POM文件。

    https://github.com/IntuitDeveloperRelations/IPP_Sample_Code/blob/master/CustomerAccountData/Java/AggCatSampleApplication/pom.xml

    谢谢


    我的构建在Eclipse中可以工作,但在MAC的命令行中失败了。问题是我漏掉了这个解决方案中的第二个构件。 <artifactId>slf4j-log4j12</artifactId>。我猜测Eclipse默认包含它。 - Sacky San
    1
    添加log4j-over-slf4j可以解决这个问题。使用slf4j-log4j12添加log4j依赖会出现错误。<dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>${slf4j-api.version}</version> </dependency> - Shubham Pandey
    我在使用spring-kafka-test和它的zookeeper依赖时遇到了错误。将slf4j-log4j12作为测试范围的依赖项添加后,问题得到了解决。 - Jack Straw
    运行得非常好。我正在使用 Big Queue https://github.com/bulldog2011/bigqueue 进行工作,然后出现了这个错误。希望这能帮助任何人。 - ahrooran

    10

    在“部署程序集”中检查。

    我遇到了同样的错误,当我使用“Maven clean install”方式生成war文件并手动部署时,它可以正常工作,但是当我使用运行时环境(Eclipse)时就会出现问题。

    对于我来说(针对Eclipse IDE),解决方案是:转到“项目属性”-->“部署程序集”-->“添加”-->“你需要的jar包”,在我的情况下是Java“构建路径条目”。也许可以帮到你一点!


    4

    根据堆栈跟踪,一个名为com.intuit.ipp.aggcat.util.SAML2AssertionGenerator的Intuit类需要在类路径上有一个saml jar。

    一个名为org.opensaml.xml.XMLConfigurator的saml类反过来需要log4j,它在WAR中但找不到它。

    其中一种解释是需要log4j的XMLConfigurator类并不在WAR内部而是在下游类加载器中发现。WAR中是否缺少saml jar?

    需要log4j的XMLConfigurator类无法在加载它的类加载器级别上找到它,并且WAR中的log4j版本对于该特定类加载器不可见。

    为了排除故障,一种方法是在oauth调用之前添加以下内容:

    System.out.println("all versions of log4j Logger: " + getClass().getClassLoader().getResources("org/apache/log4j/Logger.class") );
    
    System.out.println("all versions of XMLConfigurator: " + getClass().getClassLoader().getResources("org/opensaml/xml/XMLConfigurator.class") );
    
    System.out.println("all versions of XMLConfigurator visible from the classloader of the OAuthAuthorizer class: " + OAuthAuthorizer.class.getClassLoader().getResources("org/opensaml/xml/XMLConfigurator.class") );
    
    System.out.println("all versions of log4j visible from the classloader of the OAuthAuthorizer class: " + OAuthAuthorizer.class.getClassloader().getResources("org/apache/log4j/Logger.class") );
    

    如果您正在使用Java 7,可以查看jHades,这是我制作的一个工具,可帮助解决此类问题。

    为了查看发生了什么,请发布上面的类路径查询结果,这是在哪个容器中发生的,tomcat还是jetty?最好将所有caused by的完整堆栈跟踪放在pastebin中,以防万一。


    我已经添加了您建议的代码。只需要弄清楚如何将其粘贴,因为它对于 stackoverflow 的评论字段来说太长了。 - lovebeer84
    忘记补充了...我正在运行在Weblogic服务器11g上,所以这将是Derby服务器。 - lovebeer84

    4

    在得到了@jhadesdev的建议和其他人的解释之后,我找到了问题所在。

    在添加了代码以查看各个类加载器可见的内容后,我发现了这个问题:

    All versions of log4j Logger: 
      zip:<snip>war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
    
    All versions of log4j visible from the classloader of the OAuthAuthorizer class: 
      zip:<snip>war/WEB-INF/lib/log4j-1.2.17.jar!/org/apache/log4j/Logger.class
    
    All versions of XMLConfigurator: 
      jar:<snip>com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
      zip:<snip>war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
      zip:<snip>war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
    
    All versions of XMLConfigurator visible from the classloader of the OAuthAuthorizer class: 
      jar:<snip>com.bea.core.bea.opensaml2_1.0.0.0_6-1-0-0.jar!/org/opensaml/xml/XMLConfigurator.class
      zip:<snip>war/WEB-INF/lib/ipp-java-aggcat-v1-devkit-1.0.2.jar!/org/opensaml/xml/XMLConfigurator.class
      zip:<snip>war/WEB-INF/lib/xmltooling-1.3.1.jar!/org/opensaml/xml/XMLConfigurator.class
    

    我注意到可能正在使用另一个版本的XMLConfigurator。 我反编译了该类,并在第60行(原始堆栈跟踪中出现错误的位置)发现了以下内容:private static final Logger log = Logger.getLogger(XMLConfigurator.class);,而该类是从org.apache.log4j.Logger导入的!
    因此,正在加载和使用这个类。我的解决方法是重命名包含此文件的jar文件,因为我找不到明确或间接加载它的位置。这可能会在我实际部署时造成问题。
    感谢所有帮助以及关于类加载的必要教训。

    3

    我遇到了同样的问题,原因是Weblogic愚蠢地使用了它自己的opensaml实现。为了解决这个问题,你需要在weblogic.xml中告诉它从WEB-INF/lib加载此包的类:

        <prefer-application-packages>
            <package-name>org.opensaml.*</package-name>
        </prefer-application-packages>
    

    也许 <prefer-web-inf-classes>true</prefer-web-inf-classes> 也可以起作用。

    1
    1百万次这样做。我必须通过Eclipse编辑器编辑weblogic.xml,结果看起来像这样: wls:container-descriptor wls:prefer-application-packages wls:package-nameorg.opensaml.*</wls:package-name> </wls:prefer-application-packages> </wls:container-descriptor> - wesmantooth

    2

    java.lang.ClassNotFoundException表示类在类路径中未找到。可能是log4j版本不兼容。检查不同的log4j版本。


    如何找出是否兼容? - john k

    1
    我曾经遇到过相同的问题,对于我来说,这个方法解决了问题:
    右键点击项目 -> Maven -> 更新项目。

    maven -> update project


    1
    添加compile 'org.apache.logging.log4j:log4j-1.2-api:2.17.1',然后它将自动运行。

    1
    在我的情况下,这个错误是由于一些依赖项使用了我从类路径中删除的log4j v1.x所致。因此,我引入了 log4j-1.2-api 来桥接 v1.x 到 2.x,正如 Apache 迁移指南 建议的那样:
    在我的 build.gradle 中引入这个依赖后,错误就消失了: implementation 'org.apache.logging.log4j:log4j-1.2-api:2.17.+!!'

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接