Search code examples
javaclassloader

How and When Bootstrap jar locate../lib/rt.jar and ../lib/ext.**jar are loaded?


I have two classes listed as follows

package foo;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class CustomClassLoader extends ClassLoader {
    public CustomClassLoader(ClassLoader parent){
        super(parent);
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        System.out.println( " >>> loading " + name );

        if (name.startsWith("foo")) {
            return getClass(name);
        }
        return super.loadClass(name);
    }

    public Class getClass(String name){
        try {
            byte[] data= getClassByteData(name);
            return this.defineClass(name, data, 0, data.length);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] getClassByteData(String name) throws IOException {
        String file = name.replace(".", File.separator)+".class";
        InputStream in   = this.getClass().getResourceAsStream("/"+file);
        int length = in.available();
        byte[] datas = new byte[length];
        in.read(datas, 0, length);
        return datas;
    }
}


package foo;

public class Test {
    public static void main(String[] args) {
        System.out.println(" Who is my loader? >>" + Test.class.getClassLoader());
    }

}

Run: java -Djava.system.class.loader=foo.CustomClassLoader foo.Test

Output:

 >>> loading java.lang.System
 >>> loading java.nio.charset.Charset
 >>> loading java.lang.String
 >>> loading foo.Test
 >>> loading java.lang.Object
 >>> loading java.lang.StringBuilder
 >>> loading java.lang.Class
 >>> loading java.io.PrintStream
 Who is my loader? >>foo.CustomClassLoader@de6ced

My questions are below:

  1. Why those java.lang.System, java.nio.charset.Charset etc as above would be loaded by CustomClassLoader? In my ideas I think when I run java -Djava.system.class.loader foo.Test, JVM first searches out class foo.Test, loads it, executes the main method, and then when it detects System.out.println(), it will continue to load Class java.lang.System and java.io.PrintWriter because those classes are used by it, right?

  2. When I run a class which uses some classes located in java.lang package, those classes will also be loaded again, in my case delegated CustomClassLoader>>ExtClassLoader>>BoostrapClassLoader to load?

  3. When /lib/rt.jar and /lib/ext/**.jar are loaded, before we run a class like java foo.Test all those classes have bean loaded already?

Thanks all your help in advance!


Solution

  • To answer your questions, let's take them in turn.

    1. Java's ClassLoading mechanism is based on a delegation model where an attempt to load a class is normally delegated to parent class loaders first. If the parent class loader is able to successfully load the class, then the loaded class is passed back down the delegate chain and return by whichever class loader was originally invoked. Since you set your custom class loader as the system class loader, the JVM instantiated it as the default loader used when your application starts. It is then used to load all classes that it needs. Most of those classes (i.e. anything that doesn't start with foo.*) are delegated to the parent class loaders, which explains why you see messages about your class loader attempting to load them.

    2. Because the loading of non foo.* classes is delegated to the parent class loader, loading a system class, such as System.out, again will be handled by the parent class loader, which handles caching all loaded classes and will return the previously loaded instance.

    3. Loading of the rt.jar and lib/ext/*.jar files is handled by the parent class loader (or its parent), not you. Therefore, there is no need for your class loader to concern itself with those JAR files.

    Generally, a custom class loader is built to insure that classes can be loaded from a non-standard location, such as JARs stored in a database.