When a class is requested (either implicitly through a class reference or explicitly with class.forName
), the ClassLoader
of the calling Class
is used. This allows an Applet
or an RMI-based application to refer to other classes that have been acquired from a remote site and ensure that they are downloaded from the same location as well.
However, libraries loaded from one ClassLoader
cannot necessarily see classes loaded from another ClassLoader
.
This often occurs with Object Relational Mapping (ORM) tools such as Hibernate that use configuration files that contain class names. To load the classes, it needs to resolve class names from the application's associated ClassLoader
.
If the Hibernate library is installed in the same WAR as the webapp, this will be automatic. However, if Hibernate is stored in the webapp server's global classpath or an extension location, then it won't have visibility to the webapp's ClassLoader
.
To solve this (specifically for the benefit of RMIClassLoader
), Java 1.2 added a method to the Thread
class to provide an additional ClassLoader
that could be used as an extra source of classes called the ThreadContextClassLoader (TCCL). Each thread has its own unique instance, is accessed with getContextClassLoader
and set with setContextClassLoader
. Libraries such as Hibernate use this to resolve additional classes on demand, which they wouldn't otherwise be able to resolve through their own ClassLoader
.
The context ClassLoader
is inherited by newly created threads, which allows the context ClassLoader
to be implicitly available in any executing class. However, it suffers while using Executors
or other multi-threaded environments because it may not be the case that the initiating Thread
is the same as the one that needs to subsequently load the class.
Setting the Thread Context ClassLoader
usually takes the following form:
public void runWith(Runnable runnable, ClassLoader other) { final Thread current = Thread.currentThread(); final ClassLoader tccl = current.getContextClassLoader(); try { current.setContextClassLoader(other); runnable.run(); } finally { current.setContextClassLoader(tccl); } }
Note that this pattern explicitly expects the runnable
to either be single-threaded, or that any multi-threaded pools will be instantiated during the call (and therefore will inherit the context ClassLoader
). The Thread Context ClassLoader
typically works in constrained environments such as webapp and enterprise Java servers since they own the threading and have full control of the life cycle of the applications. They do not work as well in more dynamic environments like OSGi.
Some open source libraries require the use of the Thread Context ClassLoader
to operate correctly; however, many have been upgraded to take an explicit ClassLoader
instead of attempting to load everything via the context loader.
Alternatively, mapping tools can be passed explicit Class
instances, which avoids problems with resolving the Class
in the first place. For example, Gson
is used to deserialize a class from a JSON representation and to do so is passed a Class
instance rather than the name of a class.