Search code examples
javalog4jclassloader

log4j and the thread context classloader


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?


Solution

  • 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.