log4j 和线程上下文类加载器

发布于 2024-08-16 10:25:46 字数 1059 浏览 1 评论 0原文

我是 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”的附加程序。

我的应用程序大致是这样工作的:在 init 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 强迫我搞乱线程上下文类加载器?为什么不让我传入一个类加载器(如果不这样做,则使用默认的类加载器)而不是使用线程的类加载器?

I'm a newbie to Java and just starting to figure out the concept of class loaders. Right now I am having some issues with log4j regarding its use of the thread context classloader.

I'm getting the following errors: 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".

My application works roughly this way: On init URLClassLoader #1 is constructed and loads some classes, these classes use log4j. Later on URLClassLoader #2 is constructed (which has URLClassLoader #1 as it's parent) and loads some more classes, these classes also use log4j. When URLClassLoader #2 is used to load these classes the above error message appears (there are a couple more with the same issue).

The current workaround I did was to set the current thread context classloader to URLClassLoader #2 before loading the problematic classes, and resetting it to the old one afterwards:

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

While this works, I am not sure if it's the right approach.

Any insight on this matter will be appreciated. Also, why is log4j forcing me to mess with the thread context classloader? Why not let me pass in a class loader (and use a default one when I don't) instead of using the thread's one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黎夕旧梦 2024-08-23 10:25:46

您似乎偶然发现了 log4j(以及 Apache Commons Logging 库)的主要问题,即它们在使用时发现正确的类加载器并与之交互非常困难。 此处有非常详细的解释,并附有示例;最重要的信息是,新日志框架 SLF4J 的主要驱动力之一就是消除这些问题完全。您可能想更换它,看看您的生活是否变得更轻松。

You appear to have stumbled upon the major problem with log4j (and the Apache Commons Logging library), namely that they have a ridiculously hard time discovering and interacting with the right classloaders as they're being used. There's a very dense explanation, complete with examples, here; the take-home message is that one of the primary driving forces for the new logging framework SLF4J was to eliminate these issues entirely. You might want to swap it in and see if your life is made any easier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文