Saturday, 6 August 2016

ClassLoader in java


For the past few weeks, many questions related to ClassLoader were popping in my mind.Lets discuss these questions that I will try answer in this blog.

  • When do you need a custom classloader ?
  • If classes are loaded by classloaders , then who is responsible for loading classes of ClassLoader itself ?
  • Can a single class be loaded with different classLoaders?
  • Can Objects of same class loaded by different classloaders be compared?
  • How loadClass(String) method in ClassLoader works ?
Lets try to answer these and many other questions.

javac tool compiles java files and convert them to class files.These class files can be loaded by JVM as file , url or stream using ClassLoader.
Java has provided 3 classLoaders in its library.
  1. Bootstrap
  2. Extension
  3. Application
1. If class is loaded by bootstrap then ClassLoader returned by JVM = null
  • All class files found in rt.jar file or system property as "sun.boot.class.path"
  • For example : java.util.ArrayList
2. If class is loaded by Extension then classLoader=sun.misc.Launcher.ExtClassLoader
  • All class files found in system property as "java.ext.dirs" or $JAVA_HOME/lib/ext directory are loaded by this classLoader.
  • For example : sun.net.spi.nameservice.dns.ThreadContext
3. If class is loaded by Application then classLoader=sun.misc.Launcher.AppClassLoader
  • All class files found in system property as "java.class.path" OR path specified as -cp or -classpath command line options.
  • For example : custom classes created by us.

Now lets understand some basics about these classLoaders.

When we run main method of a class, JVM internally loads bootstrap classLoader which is a native classLoader. It loads all classes in rt.jar file.



Figure 1 : Class hierarchy for ClassLoaders




Figure 2 : ClassLoader objects created by JVM and their Association


Lets try to understand above images with some coding example :

       
public class HelloCL {
    public static void main(String args[]) {

        ClassLoader bootstrapCL = java.util.ArrayList.class.getClassLoader();
        ClassLoader extCL = sun.net.spi.nameservice.dns.ThreadContext.class.getClassLoader();
        ClassLoader appCL = HelloCL.class.getClassLoader();
   
        System.out.println(bootstrapCL);
        //null

        System.out.println(extCL.isAssignableFrom(appCL.getClass()));
        //false
        //ExtClassLoader is not parent class of AppClassLoader

        //extCL.parent == null    //true
        //appCL.parent == extCL    //true
        //parent is private attribute of ClassLoader
        //this feature can be seen via debugger.
    }
}


The above program shows that :

  • Object of classLoader for java.lang.ArrayList is null
  • There is no direct relation between AppClassLoader and ExtClassLoader
  • parent attribute(see figure 2) of ExtClassLoader object is null
  • parent attribute(see figure 2) of AppClassLoader is object of ExtClassLoader
  • ExtClassLoader and AppClassLoader are child classes of UrlClassLoader.


Rules of ClassLoader

Now lets try to summarise some basic rules regarding classLoaders.

Any class loader in java must follow four basic rules :
  1. Uniqueness : If a class is already loaded by a parent classloader then, it cannot be loaded by child classloader i.e. if a class is loaded by Extension class loader then it will not be loaded again by its child Application class loader.
  2. Delegation : ClassLoader must delegate the process of loading a class to its parent(attribute) ClassLoader. If class cannot be loaded in its parent (attribute) hierarchy then it can load this class itself. For example , class loading request first comes to Application classLoader, then it delegates this request to its parent which is Extension class loader. Before loading this class by itself, Extension class loader also delegates this request to Bootstrap class loader. So priority of loading a class is given to the parent class loader first.
  3. Visibility : A child ClassLoader can see all classes loaded by its parent(attribute) classLoader.
  4. Every loaded class in JVM is uniquely identified by combination of two things :
        4A. Fully qualified class name with package.
        4B. ClassLoader which loads this class.
    For example a class with package P1 , class name as N1 is loaded by a class loader CL1. No Class loader in the hierarchy of CL1 can load this class again. There can be some other ClassLoader in a hierarchy different from CL1 , let say CL5, such that there is no relation between CL1 and CL5, which can load this class.
So now the same class is loaded twice in a single JVM :
( P1 - N1 - CL1 )
( P1 - N1 - CL5 )

Here Class is same but there Class class objects are different.



Answering Questions to ClassLoader


Now you have some clear thoughts regarding ClassLoaders and you will be able to answer some of the questions asked above.
Lets discuss their answers one by one.

(Q) When do you need a custom classloader ?

Ans :
A class file can be taken from any of the following source : file, url or stream. There may be a situation where you want to change the behaviour of class by manipulating its byte code and then load that class via your custom classLoader.For example ASM library is used to create getters and setters of field accessors in a class.

(Q) If classes are loaded by classloaders , then who is responsible for loading classes of ClassLoader itself ?

Ans : 
JVM does this task for us natively at the boot time of our application.It creates single object of 3 class loaders i.e. Bootstrap, ExtClassLoader, AppClassLoader.

Bootstrap class loader object returned by JVM = null

parent attribute of ExtClassLoader class object = null
parent attribute of AppClassLoader class object = ExtClassLoader class object


(Q) Can a single class be loaded with different classLoaders?

Ans : 
Yes. This can be possible.Lets take a scenario for this.AppClassLoader loads our custom classes.If we create our custom classLoader and intentionally load our custom classes by this classloader (by specifying some file path to pick class files).Then same class will be loaded by two different classLoaders.

(Q) Can Objects of same class loaded by different classloaders be compared?

Ans :
When a class is loaded by different classloaders, it results in two different objects that cannot be cast to each other.
       
Target t1 = ...  //loaded by one classLoader
Target t2 = ...  //loaded by second classLoader
t1 = (Target) t2;  //ClassCastException


(Q)How loadClass(String) method in ClassLoader works ?

Ans :
1. It applies a lock on loading class in a synchronized way, such two or more parallel threads will load a class only once.

2. First it checks in the parent (attribute) classLoader .

2A. If parent is null , check if bootstrap has loaded this class.
2B. If parent is not null , go for a recursive call of parent.loadClass(className, false)

3. If still we didn't find any Class class object for this name, call UrlClassLoader#findClass() method


4. UrlClassLoader#findClass() method checks for compiled class file in the file path specific to that ClassLoader.Every classloader in java has defined a file path from class files can be read as byte array.



       
protected Class loadClass(String name, boolean resolve)
  throws ClassNotFoundException
    {
#1      synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
#2B                     c = parent.loadClass(name, false);
                    } else {
#2A                     c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
#3,4                c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }



Hope you got many things clear about classloaders.Some readers may still got a question for "How to create a custom ClassLoader ?"  still not answered.


I think that could be a homework task for every reader. I may only give some hints for creating your own.

First you need to read class sun.misc.Launcher that has declared ClassLoader classes itself as static and default.You will get a lot of ideas for creating custom ClassLoaders after reading that code.

There are many other things that you should keep in mind :


  • Inherit your custom classLoader with UrlClassLoader.
  • Specify parent property to null , so that bootstrap will be its parent.
  • Specify a particular file path to read class file as byte stream.
  • You can also make a hierarchy of classloaders , but keep in mind to set their parent attribute properly.


Thanks

2 comments: