log4j和线程上下文类加载器

我是Java的新手,刚刚开始弄清楚类加载器的概念。 现在我对log4j有一些关于它使用线程上下文类加载器的问题。

我收到以下错误: A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable. The class "org.apache.log4j.Appender" was loaded by [java.net.URLClassLoader@105691e] whereas object of type "org.apache.log4j.ConsoleAppender" was loaded by [sun.misc.Launcher$AppClassLoader@16930e2]. Could not instantiate appender named "CONSOLE". A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable. The class "org.apache.log4j.Appender" was loaded by [java.net.URLClassLoader@105691e] whereas object of type "org.apache.log4j.ConsoleAppender" was loaded by [sun.misc.Launcher$AppClassLoader@16930e2]. Could not instantiate appender named "CONSOLE".

我的应用程序大致以这种方式工作:在初始化URLClassLoader#1构造并加载一些类,这些类使用log4j。 后来构建了URLClassLoader#2(它的URLClassLoader#1作为它的父级)并加载了更多的类,这些类也使用log4j。 当URLClassLoader#2用于加载这些类时,会出现上述错误消息(还有一些问题存在同一问题)。

我当前的解决方法是在加载有问题的类之前将当前线程上下文类加载器设置为URLClassLoader#2,然后将其重置为旧类:

 ClassLoader urlClassLoader; // this is URLClassLoader #2 Thread thread = Thread.currentThread(); ClassLoader loader = thread.getContextClassLoader(); thread.setContextClassLoader(urlClassLoader); try { urlClassLoader.loadClass(...) } finally { thread.setContextClassLoader(loader); } 

虽然这有效,但我不确定它是否是正确的方法。

任何有关此事的见解将不胜感激。 另外,为什么log4j迫使我搞乱线程上下文类加载器? 为什么不让我传入一个类加载器(当我没有时使用默认的加载器)而不是使用线程的?

您似乎偶然发现了log4j(以及Apache Commons Logging库)的主要问题,即他们在使用时发现并与正确的类加载器进行交互时非常困难。 这里有一个非常密集的解释,有完整的例子; 带回家的信息是,新的日志框架SLF4J的主要推动力之一就是完全消除这些问题。 你可能想要交换它,看看你的生活是否变得更容易。