ThreadContextClassLoaders

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.

Note

Note that Hibernate has been upgraded to support OSGi since version 4.2, and provides an EntityManagerFactory as an OSGi service.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset