Java log4j和线程上下文类加载器

Java log4j和线程上下文类加载器,java,log4j,classloader,Java,Log4j,Classloader,我是Java的新手,刚刚开始理解类加载器的概念。现在我对log4j在使用线程上下文类加载器方面遇到了一些问题 我收到以下错误:org.apache.log4j.ConsoleAppender对象不能分配给“org.apache.log4j.Appender”变量。类“org.apache.log4j.Appender”是由[java.net]加载的。URLClassLoader@105691e]而类型为“org.apache.log4j.ConsoleAppender”的对象是由[sun.mis

我是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].  无法实例化名为“控制台”的追加器。

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

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

我不确定现在开始使用其他东西是否可行。处理这个log4j问题的建议方法是什么?老实说,我不能说,因为这是一个非常糟糕的问题,我现在极力避免使用log4j和apachecommons日志。但实际上,您应该能够轻松地迁移到SLF4J——有关SLF4J如何配备“桥接适配器”的信息,请参阅,这些适配器允许您的代码仍然对log4j进行调用,并让这些调用被SLF4J截获。通过这种方式,您可以在任何新代码中本机使用SLF4J,并在空闲时将旧的、使用log4j的代码迁移到SLF4J。+1作为避免使用log4j和JCL的提示。它们被SLF4j取代,SLF4j还具有log4j和jcl的兼容层。我们在所有的项目中都是出于这些原因而这样做的。你有没有文章解释为什么要避免log4j?没有背景知识,我真的不能提出这样的建议。还有一些关于SLF4j作为新“标准”的信息可以帮助你。丹尼尔,链接文章(“密集解释”链接)解释了这个问题,你遇到的问题应该是最好的例子。你的问题救了我的命,我被类似的问题绊倒了3天!我还没有设置“thread.setContextClassLoader”,这样就可以了!这真的很好,尽管你是java的新手!