Difference Between Thread's Context Class Loader and Normal Classloader

Difference between thread's context class loader and normal classloader

Each class will use its own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the classloader of ClassA, or its parents.

The thread context classloader is the current classloader for the current thread. An object can be created from a class in ClassLoaderC and then passed to a thread owned by ClassLoaderD. In this case the object needs to use Thread.currentThread().getContextClassLoader() directly if it wants to load resources that are not available on its own classloader.

Difference between Thread.currentThread() classLoader and normal classLoader

Thread.currentThread().getContextClassLoader()

Returns the context
ClassLoader for this Thread. The context ClassLoader is provided by
the creator of the thread for use by code running in this thread when
loading classes and resources. If not set, the default is the
ClassLoader context of the parent Thread. The context ClassLoader of
the primordial thread is typically set to the class loader used to
load the application.

Class#getClassLoader()

Returns the class loader for the class. Some implementations may use
null to represent the bootstrap class loader. This method will return
null in such implementations if this class was loaded by the bootstrap
class loader.


In a nutshell:

Thread.currentThread().getContextClassLoader() is the ClassLoader of the context of the thread that has been set with setContextClassLoader(ClassLoader cl). Imagine that you have a complex java application with a hierarchy of ClassLoader (for example an Application Server) and you want your current thread to load classes or resources from one specific ClassLoader in this hierarchy, you can do it by simply setting the context ClassLoader of the thread to this specific ClassLoader.

Class#getClassLoader() is simply the ClassLoader from which your instance of Class has been loaded.

Java Thread context classloader - how does it work?

In OSGi the Thread Context ClassLoader (TCCL) is simply undefined. You cannot expect or assert that it will be anything in particular. In fact, a lot of the time it will be null.

TCCL is a hack that was added in Java 1.2 to support J2EE. Specifically it was needed to support things like Entity Beans; in a modern world it's used to support technologies like JPA, JAXB, Hibernate and so on.

The issue with parent delegation is that, while the application classes at the bottom have visibility of all classes in the parent classloaders, unfortunately the classes loaded by the parent classloaders do not have visibility of the application classes. In practical terms, this means that your application code can load (say) the classes that make up Hibernate, but Hibernate would not be able to load your domain classes because they are below it in the hierarchy.

So, TCCL was invented. In a J2EE application server, the TCCL is created as a thread-local variable, and it has visibility of all your application classes. Hibernate/JPA/JAXB etc can consult the TCCL in order to find the application classes. This was easy enough to do in J2EE because the app server controls all of the entry points: it controls the web server, it controls the RMI endpoints, and as an application developer you are not permitted to create your own threads.

However the programming environment for OSGi is far less constrained. Any bundle is permitted to create its own network endpoints, spin up its own threads, or pretty much do anything. Therefore, OSGi has no opportunity to intervene and impose a TCCL that has visibility of the application classes. Furthermore, the very concept of an "application" is fuzzy because we have this neat thing called modularity. An application consists of multiple bundles... but how to define which bundles may provide classes to the TCCL?

So OSGi basically punts on this issue. The TCCL is undefined so you should never rely on it. Fortunately most libraries that try to use only do so as one of a series of places they try to load classes from.

context class loader

From this thread:

Class.getClassLoader() returns the ClassLoader that loaded the class it is invoked on.

Thread.getContextClassLoader() returns the ClassLoader set as the context ClassLoader for the Thread it is invoked on, which can be different from the ClassLoader that loaded the Thread class itself if the Thread's setContextClassLoader(ClassLoader) method has been invoked.

This can be used to allow the object starting a thread to specify a ClassLoader that objects running in the thread should use, but the cooperation of some of those objects is required for that to work.

So if you are wondering why there are 3 API calls

Thread<instance>.getContextClassLoader()
Thread<instance>.getClassLoader()
Class<instance>.getClassLoader()

, you can find in this Find a way out of the ClassLoader maze an answer.

Why do thread context classloaders exist in the first place? They were introduced in J2SE without much fanfare. A certain lack of proper guidance and documentation from Sun Microsystems likely explains why many developers find them confusing.

In truth, context classloaders provide a back door around the classloading delegation scheme also introduced in J2SE. Normally, all classloaders in a JVM are organized in a hierarchy such that every classloader (except for the primordial classloader that bootstraps the entire JVM) has a single parent.

[...] To make matters worse, certain application servers set context and current classloaders to different ClassLoader instances that have the same classpaths and yet are not related as a delegation parent and child.

Java classloader: difference between defining loader & initiating loader?

Classloaders usually follow a delegation mechanism.


Suppose the delegation hierarchy is L->Lp->Lq and the class is defined in Lp

In this case,

L will delegate the class loading to Lp,

Lp will delegate to Lq

Lq will not load the class and the call returns back to Lp.

Lp will load the class since it is defined in Lp and the call returns back to L.


Here Lp and L are the initiating class loaders and Lp is the defining class loader.


Similarly if the delegation heirarchy is L->Lp and the class is defined in L,
L becomes the defining and initiating class loader.

Lp is not the initiating class loader.


Simply put, if the class loader is able to return a reference to the Class instance in the delegation chain, it is an initiating class loader.



Related Topics



Leave a reply



Submit