当前位置: 首页 > 知识库问答 >
问题:

不同Log4j类上的不同ClassNotFoundException

唐炜
2023-03-14

我们在一个基于Swing/Spring的大型应用程序中看到以下异常。该错误发生在用户交互过程中,触发Spring通过commons loggingwarn(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、log4j-1.2.17、commons-logging-1.1.1、spring-4.1.2上的Java 8u40
  • 未使用OSGI、web容器等类加载基础设施
  • 没有使用Java代理、探查器和测试工具
  • 没有异常的-XX或-D参数
  • 通过System.get属性(java.class.path)手动打印类路径,以验证log4j JAR是否存在-是的,并且只有一个版本存在1.2.17
  • 不能加载的类在运行之间变化,有时是ThowableInformation,有时是ThrowableRenader等,但它总是失败。
  • 如果以下内容被放置在应用程序静态无效main()中,那么log4j类被正确加载,并且在控制台中看到警告并且异常不会在以后发生。

密码

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。杂项。URLClassPath。debug=true用于调试类加载的JVM选项。。。这表明各种类都是从log4jjar加载的

例如

[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类型的加载程序
    • 我找到了$JarLoader的实例,它引用了log4j-1.2.17
    • 即使太阳也是如此。杂项。Launcher$AppClassLoader以前从JAR加载了log4j类,但似乎它不再能够
    • 我所看到的早期类加载工作和后期类加载失败之间的唯一区别是,URLClassPath$JarLoader的closed属性在失败时设置为true
    • 已达到某些资源限制,无法再加载类,但由于某些原因,未报告此情况
    • Spring、CoreJava或commons日志记录使用的是私有类加载基础设施,无法看到Log4JJAR
    • 还有人反对这个吗

共有1个答案

章学义
2023-03-14

URLClassLoader已经关闭,这带来了Java报告ClassNotFoundException的不幸后果。

为了支持使用OSGI/Spring-DM的应用程序的早期版本,我们在Spring XML中有bean,它允许从正确的捆绑包加载资源,这是一个可怕的黑客攻击,但在给定代码的时候,这是唯一可以做到的方法,资源和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,因为它没有任何好处,但是现在遗留的PluginModuleClassLoader机制由于从60个捆绑包中删除它的成本而保留了下来。

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

 类似资料:
  • 对于一些人来说,这可能是一个非常简单的问题,但就我个人而言,Log4j配置非常困难,学习执行脑部手术可能没有那么困难。 我正试图让多个日志记录者登录到不同的文件。这是我的log4j中的内容。属性文件: 这是我的(非常简单的)Java应用程序用于测试配置: 我有两个问题: 有一个问题,我总是在

  • 问题内容: 我想使用Log4J记录我的Java项目。我在src目录中创建了一个log4j.properties文件,其内容如下: 例如,我只想在我的主要方法中使用“ DEFAULT_LOGGER”。所以我写道: 但是,当我执行main方法时,我将消息“ Process Logger”打印到所有Appender(stdout,file和file2),但是我只想将其打印到file2。我该怎么做,或者更

  • 我想根据不同的模块登录不同的应用程序... 我有3个附件:控制台,一个用于记录控制器和服务的滚动文件,另一个用于记录作业中的某些内容的滚动文件。我只想为其滚动文件记录作业的代码,并只使用另一个滚动文件记录控制器和服务。 这是我的grails log4j配置: 使用此配置,日志将写入两个滚动文件和标准输出。如果从根目录中删除滚动附加器,滚动文件将保持为空,即使为文件组指定了附加器。 有人建议将日志分

  • 我(目前)有三个按钮 使用这些按钮,我想显示不同的菜单/覆盖。覆盖图如下所示: 这方面的JS是: 我的问题是只有菜单1正在显示。脚本可以正常工作,但是menu2和menu3没有显示。 我想这一定是缺少的东西。也许是a$(this)什么的(对不起我的JS已经不是以前的样子了)。我在中循环,然后从google chrome dev中点击了“Right”按钮(我想,很难说出来)。 预期结果:如果我按下按

  • 想象一下下面的scanario:我有一个程序,它要求输入一个整数,然后是一个String输入。 根据aobe代码,我没有机会输入姓名。因此,通常我会声明2个扫描仪对象,如下所示: 我的问题是:有必要声明多个扫描仪对象来接受不同类型的输入吗??我这样做是正确的吗? 我已经考虑这个问题很多年了。(SO中的几个问题提到了多扫描仪,但他们的问题只使用了一个扫描仪对象,所以我今天问这个问题。)

  • 下面,我有一个全局应用的日志回溯配置。 我想全局使日志记录级别错误,除了一个类。对于一个特定的类,我想使日志记录级别 INFO。我该怎么做?