Friday, January 22, 2010

Simple Custom ClassLoader

ClassLoader is provisioning us to bring the JAVA Class to executable format. JAVA SE comes with default ClassLoader and URLClassLoader. First one is called SystemClassLoader, which will access the classes from bootstrap path, classpath, JAVA extension and library. If our application wants to access Class from external URL then URLClassLoader will be useful. If requested class found in specified URLs, then that gets priority than Classpath classes.

Static Classloader will load all the classes from the classpath in startup itself. This class loader is not capable of reloading modified classes from jars in the JVM runtime.

Dynamic Classloader will load classes on demand basis and capable of reloading classes anything found changed.

Custom Classloader will be useful for plugin based applications, application servers and etc., This helps to load and remove class definitions from the JVM. For instance, we are creating instance of class from .class file, if we want to create class from .cls file. We can achive this from Custom Classloader, just implementing two APIs loadClass(), and findClass()

Custom ClassLoader

Custom classloader has to take care of following responsibilities.

  1. Make sure Class not loaded already by any of the parent classloader including system loader
  2. Find Class from repository
  3. Fefine the class by loading the bytes and resolve if needed
  4. Return the class

LoadClass

loadClass() method gets called whenever we try to access new Class. This API is responsible of check

  • Is this class name loaded by current context classloader ?
  • If not found, check parent classloader
  • If no parent found, then check findBootstrapClass loader
  • If none of the above mentioned step aware of Class then call findClass()
In general, we do not need to rewrite this API. It may come necessary, if we wants to change this order or some other thing.

FindClass

findClass method aligns or corrects the Class name to point the actual resource. If we wants to create instance of the String, then we will pass the class name as java.lang.String and Classloader will construct URL as java/lang/String.class and finds this resource from classpath.

In custom Classloader, we may need to give additionally the repository of classes location if we are accessing class form other than classpath.

CustomClassLoader.java

import java.io.FileInputStream;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class CustomClassLoader extends ClassLoader {

 String repoLocation = "/tmp/";

 public CustomClassLoader() { }
 
 public CustomClassLoader(ClassLoader parent) {
  super(parent);
 }
 
 @Override
 protected Class<?> findClass(final String name)
   throws ClassNotFoundException {

  AccessControlContext acc = AccessController.getContext();

  try {
   return (Class)AccessController.doPrivileged(
     new PrivilegedExceptionAction() {
      public Object run() throws ClassNotFoundException {

       FileInputStream fi = null;
       try {

        String path = name.replace('.', '/');
        fi = new FileInputStream(repoLocation + path
          + ".cls");
        byte[] classBytes = new byte[fi.available()];
        fi.read(classBytes);
        return defineClass(name, classBytes, 0,
          classBytes.length);
       }catch(Exception e )
       {
        throw new ClassNotFoundException(name);
       }
      }
     }, acc);
  } catch (java.security.PrivilegedActionException pae) {
   return super.findClass(name);
  }
 }
 
 public static void main(String[] args) throws Exception{
  ClassLoader cls= new CustomClassLoader(ClassLoader.getSystemClassLoader());
  Class stringClass=cls.loadClass("ABC");
  stringClass.newInstance();
 }
}
ABC.java

public class ABC {
 public ABC() {
 System.out.println("Hello");
 }
}

After compiling these two classes, rename the ABC.class to ABC.cls and then run java CustomClassLoader

Now, simple class loader which loads class from .cls file.

If we use MANIFEST.MF in jar files to define the package, then attributes will be read using java.util.jar.Manifest. Based on these attributes ClassLoader will behave.

Similar to finding Class from ClassLoader, we can overwrite findResource() and findLibrary() to alter the approach of loading resources and libraries

Recent Posts

Unix Commands | List all My Posts

Texts

This blog intended to share the knowledge and contribute to JAVA Community such a way that by providing samples and pointing right documents/webpages. We try to give our knowledege level best and no guarantee can be claimed on truth. Copyright and Terms of Policy refer blogspot.com