首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在不同的ClassNotFoundException类上改变Log4j

在不同的ClassNotFoundException类上改变Log4j
EN

Stack Overflow用户
提问于 2015-08-13 14:33:51
回答 1查看 969关注 0票数 1

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

代码语言:javascript
复制
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 SP3上的Java8u40,log4j-1.2.17,1.1.1,Spring4.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在应用程序中是可见的,假设没有多个类加载器.

代码

代码语言:javascript
复制
Log logger = LogFactory.getLog(getClass());
logger.warn("foo", new Exception());
  • 成功引用了不能在以后从应用程序入口加载的类,例如ThowableInformation

代码

代码语言:javascript
复制
380        if (result == null) {
381            throw new ClassNotFoundException(name); // <=== here 
382        }
383        return result;
  • 在IOException中放置断点,以防出现“太多打开的文件”错误--没有触发。
  • 使用-verbose和-Dsun.misc.URLClassPath.debug=true JVM选项来调试类加载.这表明从log4j jar加载了各种类.

例如

代码语言:javascript
复制
[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失败时,它的关闭属性被设置为true .

我的理论

  • 达到了某些资源限制,无法再加载类,但由于某种原因,没有报告这一点。
  • Spring、核心Java或commons正在使用一个私有类加载基础结构,无法看到log4j JAR。

我的问题

  • 还有其他人会反对吗?
  • ClassNotFoundException的可能原因可能是间歇性的?我怎么能困住他们?
  • 更多的调试建议-我已经没有想法了。
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-08-14 12:55:58

根本原因

URLClassLoader已经关闭,这对Java产生了不幸的影响。

背景

为了支持使用OSGI/ spring的应用程序的早期版本,我们在spring中使用了bean,允许从正确的包中加载资源,这是一个可怕的攻击,但在给定的代码、资源和XML文件中,唯一可以做到的方法是在不同的包中.

代码语言:javascript
复制
<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+包中删除它的成本,现在遗留的60+机制仍然存在。

它是如何被关闭的

用户交互关闭一个应用程序上下文并加载另一个应用程序上下文.这有破坏应用程序上下文的副作用。春天会自动摧毁所有的豆子。在classLoader bean的情况下,它调用自动查找close()方法,即URLClassLoader.close(),这意味着所有后续的外观都会在ClassNotFoundException中失败

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31991224

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档