log4j和线程上下文类加载器

14

我是Java的新手,刚开始学习类加载器的概念。目前我在使用log4j时遇到了一些问题,涉及到线程上下文类加载器的使用。

我得到了以下错误信息:"org.apache.log4j.ConsoleAppender"对象无法分配给"org.apache.log4j.Appender"变量。类"org.apache.log4j.Appender"由[java.net.URLClassLoader@105691e]加载,而类型为"org.apache.log4j.ConsoleAppender"的对象由[sun.misc.Launcher$AppClassLoader@16930e2]加载。无法实例化名为"CONSOLE"的appender。

我的应用程序大致工作方式如下:在初始化时,构造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强制我使用线程上下文类加载器?为什么不让我传递一个类加载器(当我不使用时使用默认值)而不是使用线程上下文类加载器?


你的问题解救了我,我被类似的问题困扰了三天!我没有设置“thread.setContextClassLoader”,有了它就没问题了!尽管你是Java的新手,但真的很棒! - Daniel Hári
1个回答

15

您似乎遇到了log4j(以及Apache Commons Logging库)的主要问题,即它们在使用时很难发现和与正确的类加载器进行交互。这里有一个非常密集的解释,包括示例,请参见此处;简单来说,新日志框架SLF4J 的主要驱动力之一是完全消除这些问题。您可能需要将其替换并查看是否使您的生活更轻松。


我不确定在这个阶段我们是否能够开始使用其他东西。处理这个log4j问题的建议方法是什么? - Idan K
1
说实话,我不能确定,因为这是一个很糟糕的问题,所以我现在都会避免使用log4j和Apache Commons Logging。但是从实际情况来看,你应该可以轻松地迁移到SLF4J——请参阅http://www.slf4j.org/legacy.html,了解SLF4J如何提供“桥接适配器”,使您的代码仍然可以调用log4j,并且这些调用将被SLF4J拦截。这样,您就可以在任何新代码中本地使用SLF4J,并在方便时将旧的、使用log4j的代码迁移到SLF4J上。 - delfuego
+1 避免使用 Log4j 和 JCL 的提示。它们已被 SLF4j 取代,该库还具有与 log4j 和 jcl 的兼容层。我们在所有项目中都这样做了,正是出于这些原因。 - mhaller
你有没有任何解释为什么要避免使用log4j的文章?我真的无法在没有一些背景知识的情况下提出这样的建议。此外,一些关于SLF4j成为新“标准”的信息也可能会有所帮助。 - Idan K
Daniel,链接的文章(“密集解释”链接)解释了问题,而你遇到的问题应该是最好的例子。 - delfuego
谢谢,我会研究一下,并在SO上提出其他关于SLF4j的问题。 - Idan K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接