我们在基于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
System.getProperty("java.class.path")
手动打印出类路径以验证log4j JAR是否存在 - 是的,只有一个版本存在1.2.17 static void main()
中,则会正确加载log4j类,并在控制台中看到警告,以后不会发生异常。 &lt; ==这确认了应用程序中可以看到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;
例如
[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]
答案 0 :(得分:0)
URLClassLoader已关闭,这会产生Java报告ClassNotFoundException的不幸影响。
为了支持使用OSGI / Spring-DM的应用程序的早期版本,我们在spring XML中使用bean,允许从正确的bundle中加载资源,这是一个可怕的hack,但它唯一的方法是在给定代码,资源和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多个捆绑包中删除它的成本,现在保留了现有的PluginModuleClassLoader机制。 / p>
有问题的用户交互会关闭一个应用程序上下文并加载另一个...这会产生破坏应用程序上下文的副作用。 Spring会自动销毁所有bean。对于classLoader bean,它调用自动查找close()方法,即URLClassLoader.close(),这意味着所有后续的查找都会因ClassNotFoundException而失败