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 thisThread
. The contextClassLoader
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 contextClassLoader
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 theClassLoader
that loaded the class it is invoked on.
Thread.getContextClassLoader()
returns theClassLoader
set as the contextClassLoader
for theThread
it is invoked on, which can be different from theClassLoader
that loaded the Thread class itself if the Thread'ssetContextClassLoader(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
Module Error When Running Javafx Media Application
Slf4J: Failed to Load Class "Org.Slf4J.Impl.Staticloggerbinder"
Convert Java.Util.Date to Java.Time.Localdate
How to Set the Classpath in Netbeans
How to Make an Image Move While Listening to a Keypress in Java
What Is @Modelattribute in Spring MVC
How to Tell If I'm Running in 64-Bit Jvm or 32-Bit Jvm (From Within a Program)
Java Class That Implements Map and Keeps Insertion Order
Swing Grouplayout: Resizing and Limiting Component Sizes
Using Prepared Statements to Set Table Name
How to Initialise a Static Map
What Is the Point of "Final Class" in Java
How to Map a Composite Key with JPA and Hibernate
Why Is Java's Simpledateformat Not Thread-Safe