Java Language Implementing a custom classLoader


Example

Every custom loader must directly or indirectly extend the java.lang.ClassLoader class. The main extension points are the following methods:

  • findClass(String) - overload this method if your classloader follows the standard delegation model for class loading.
  • loadClass(String, boolean) - overload this method to implement an alternative delegation model.
  • findResource and findResources - overload these methods to customize resource loading.

The defineClass methods which are responsible for actually loading the class from a byte array are final to prevent overloading. Any custom behavior needs to be performed prior to calling defineClass.

Here is a simple that loads a specific class from a byte array:

public class ByteArrayClassLoader extends ClassLoader {
    private String classname;
    private byte[] classfile;

    public ByteArrayClassLoader(String classname, byte[] classfile) {
        this.classname = classname;
        this.classfile = classfile.clone();
    }

    @Override
    protected Class findClass(String classname) throws ClassNotFoundException {
        if (classname.equals(this.classname)) {
            return defineClass(classname, classfile, 0, classfile.length);
        } else {
            throw new ClassNotFoundException(classname);
        }
    }
}

Since we have only overridden the findClass method, this custom class loader is going to behave as follows when loadClass is called.

  1. The classloader's loadClass method calls findLoadedClass to see if a class with this name has already been loaded by this classloader. If that succeeds, the resulting Class object is returned to the requestor.
  2. The loadClass method then delegates to the parent classloader by calling its loadClass call. If the parent can deal with the request, it will return a Class object which is then returned to the requestor.
  3. If the parent classloader cannot load the class, findClass then calls our override findClass method, passing the name of the class to be loaded.
  4. If the requested name matches this.classname, we call defineClass to load the actual class from the this.classfile byte array. The resulting Class object is then returned.
  5. If the name did not match, we throw ClassNotFoundException.