Understand ClassLoader -- Introduction


(Apparently, I'm not a native English speaker. So feel free to figure out any grammar errors or typos. I'll be very appreciated.☺)

Almost every Java programmer has came across the following two Exceptions, ClassNotFoundException and ClassCastException. When the program you written shutdown or misbehaved because of them, don’t be panic. There is no magic inside JVM. This is just a reminder that you need to learn something new. After reading this post, you will understand where these exceptions come from and how to play with them :)

What is ClassLoader

We know that a Java program is compiled into byte code which is loaded and executed inside JVM. Byte code is nothing but some JVM understandable commands. You can decompress a jar file and read the byte code directly in the resulting class files. You may wonder that how JVM loads these classes.

When a Java software is started, no matter it’s a GUI program or an enterprise program such as Tomcat server, an instance of JVM is created within a new process. After something mysterious happened, the JVM realizes that it’s the time to load classes into itself. And then it takes out the Bootstrap class loader from its toolbox.

The Bootstrap class loader is a special class loader which equals NULL and acts as the ancestor of all other class loaders. Its responsibility is to load the core Java libraries. Some classes you are familiar with such as java.lang.Object and java.lang.Thread are loaded by it.

Do you still remember the exciting moment when your hello world program first ran and said hello to this world? We have been told that a program starts to run from the main method of the Main class. Now a question comes to mind. How is the Main class loaded? The answer is by Application class loader which is an instance of sum.misc.Launcher$AppClassLoader.

All classes found on java.class.path, which maps to the CLASSPATH environment variable, are loaded by it. It is an alias name of System class loader, which can be retrieved by calling ClassLoader.getSystemClassLoader(). The classes required by Main class are loaded by the same class loader of Main by default.

Every class loader but Bootstrap class loader has a parent. The parent of Application class loader is the Extension class loader whose parent is Bootstrap class loader. The Extension class loader is an instance of sun.misc.Launcher$ExtClassLoader and is responsible to load the code in the extension directories $JAVA_HOME/jre/lib/ext or others specified by the java.ext.dirs property. The relationship of these three class loaders can be described in the following graph.

relationship of class loaders

ClassLoader Delegation Model

Next, we will talk about the ClassLoader Delegation Model. When a class bar is required from class foo, the classloader of class foo tries to check if bar has already been loaded by it. If no loaded class is found, it asks its parent to find class bar, which means it delegates the job to its parent. If its parent and ancestors fail to find the loaded class too, it will attempt to load and initiate class bar by itself.

Finally a ClassNotFoundException will be thrown if there exists no class loader can find or load the required class. The benefit of CDM is to prevent the less-trusted code from replacing the core libraries.
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        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.
                    // This is the defining class loader of c.
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

Class Isolation

Every class has a class loader associated with it. It’s called the defining class loader of the class. We know that two classes with different package names or class names are different classes. But the classes with exactly the same signature can also be considered different, if they are loaded by different class loaders. We call it the class isolation by class loader. Isn’t it awesome!

I’ll explain it in detail in my next post and illustrate how to define your own custom class loader.

Understand ClassLoader Series

1. Understand ClassLoader -- Introduction
2. Understand ClassLoader -- Custom ClassLoader
3. Understand ClassLoader -- Dynamically Load Classes in Android

Comments

Post a Comment