gpt4 book ai didi

java - 各种 Log4j 类上的不同 ClassNotFoundException

转载 作者:太空宇宙 更新时间:2023-11-04 13:32:54 25 4
gpt4 key购买 nike

我们在基于 Swing/Spring 的大型应用程序中看到以下异常。该错误发生在用户交互期间,触发 Spring 通过 commons-logging warn(String, Throwable) 报告警告,进而调用 log4j。不幸的是,我无法将这个问题分解为一个独立的示例。

Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/apache/log4j/spi/ThrowableInformation
at org.apache.log4j.spi.LoggingEvent.<init>(LoggingEvent.java:165)
at org.apache.log4j.Category.forcedLog(Category.java:391)
at org.apache.log4j.Category.log(Category.java:856)
at org.apache.commons.logging.impl.Log4JLogger.warn(Log4JLogger.java:234)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:487)
<company specific code>
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:749)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:702)
at java.awt.EventQueue$3.run(EventQueue.java:696)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:719)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.spi.ThrowableInformation
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 27 more

环境

  • Windows XP SP3 上的 Java 8u40、log4j-1.2.17、commons-logging-1.1.1、spring-4.1.2
  • 未使用 OSGI、Web 容器等类加载基础设施
  • 未使用 Java 代理、分析器、测试工具
  • 没有异常的 -XX 或 -D 参数

观察/我尝试过的事情

  • 通过 System.getProperty("java.class.path") 手动打印类路径以验证 log4j JAR 是否存在 - 是的,并且仅存在一个版本 1.2.17
  • 无法加载的类因运行而异,有时是 ThowableInformation,有时是 ThrowableRenderer 等,但总是失败。
  • 如果将以下内容放置在应用程序中 static void main(),则 log4j 类将正确加载,并在控制台中看到警告,并且稍后不会发生异常。 <== 这确认了 log4j JAR 从应用程序中可见,假设没有多个类加载器在使用...

代码

Log logger = LogFactory.getLog(getClass());
logger.warn("foo", new Exception());
  • 成功引用了稍后无法从应用程序入口点加载的类,例如可索取的信息

代码

380        if (result == null) {
381 throw new ClassNotFoundException(name); // <=== here
382 }
383 return result;
  • 在 IOException 中放置断点,以防出现“打开文件过多”错误 - 未触发。
  • 使用 -verbose 和 -Dsun.misc.URLClassPath.debug=true J​​VM 选项来调试类加载...这表明各种类是从 log4j jar 加载的...

例如

[Loaded org.apache.log4j.Category from file:/<path redacted>/log5j-1.2.17.jar]
[Loaded org.apache.log4j.Logger from file:/<path redacted>/log5j-1.2.17.jar]
[Loaded org.apache.log4j.Priority from file:/<path redacted>/log5j-1.2.17.jar]
  • 在 ClassNotFoundException 中放置断点以了解更多信息
    • 我可以看到 Launcher$AppClassLoader 有一个 URLClassLoader ucp
    • ucp 包含 URLClassPath$FileLoader 和 URLClassPath$JarLoader 类型的加载器
    • 我找到了引用 log4j-1.2.17 的 $JarLoader 实例。
    • 尽管 sun.misc.Launcher$AppClassLoader 的同一实例之前从 JAR 加载了 log4j 类,但它似乎不再能够...
    • 我能看到早期的类加载工作和后来的类加载失败之间的唯一区别是 URLClassPath$JarLoader 的 close 属性在失败时设置为 true...

我的理论

  • 已达到某些资源限制,无法再加载类,但由于某种原因,未报告此情况。
  • Spring、核心 Java 或 commons-logging 使用私有(private)类加载基础结构,无法看到 log4j JAR。

我的问题

  • 还有其他人遇到过这种情况吗?
  • 间歇性出现 ClassNotFoundException 的可能原因是什么?我怎样才能困住他们?
  • 更多调试建议 - 我已经没有主意了。

最佳答案

根本原因

URLClassLoader 已关闭,这会导致 Java 报告 ClassNotFoundException。

背景

为了支持使用 OSGI/Spring-DM 的应用程序的早期版本,我们在 Spring XML 中添加了 beans,允许从正确的包中加载资源,这是一个可怕的黑客行为,但在给定代码、资源和 XML 文件时可以完成的唯一方法是在不同的包中......

<bean id="classLoader" class="org.example.internal.PluginModuleClassLoader" factory-method="getClassLoader" />
<bean id="imageLoader" class="org.example.ImageLoader">
<property name="classLoader" ref="classLoader" />
</bean>

public class PluginModuleClassLoader {
public static ClassLoader getClassLoader() {
return PluginModuleClassLoader.class.getClassLoader();
}
}

我们在 6 个月前将 Spring 从(2.5.5 到 4.1.2)升级,并删除了 OSGI,因为它没有任何好处,但是由于从 60 多个 bundle 中删除它的成本,现在遗留的 PluginModuleClassLoader 机制仍然保留。

它是如何关闭的

相关的用户交互会关闭一个应用程序上下文并加载另一个...这会产生破坏应用程序上下文的副作用。 Spring自动销毁所有bean。对于 classLoader bean,它会自动调用查找 close() 方法,即 URLClassLoader.close(),这意味着所有后续查找都会失败并出现 ClassNotFoundException

关于java - 各种 Log4j 类上的不同 ClassNotFoundException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31991224/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com