Sunday, 26 January 2014

Java Class Loader - An easy explanation for beginners

What is Java Class Loader


A Class Loader is an object that is responsible for loading the classes. It takes class name (with full package notation. Ex: java.lang.Object) as an input and attempts to locate or construct the class. Class loader loads classes in a platform dependent manner.

When Classes needs to be Loaded?

Class loading can happen in the following situation.

  • when a class has public static void main

  • when the static method of a class is called

  • when a instance of a class is created

  • when calling the class using reflection libraries (class.forName)


Types of Class Loaders


Bootstrap Class Loader:
As of Java 1.2, Bootstrap class loader is embedded inside JVM. It is the parent of all the other class loaders.This class loader loads the run time environment. (\jre\lib\rt.jar).

Extension Class Loader:
Extension class loader is the next level class loader and it has bootstrap as a parent. It loads the extension libraries from \jre\lib\ext\.

System Class Loader:
System class loader is the next level of Extension class loader and it loads the classes from the CLASSPATH.

Custom Class Loader:
JVM also supports custom class loaders creation. It can be created by extending the java.lang.ClassLoader class and overriding the loadClass() method.

Class Loader Principles:


There are mainly three principles followed in Class Loader.

Delegation:
Whenever the JVM requests for the class loader, the class loader consult it's parents before attempting to service it by itself. This principle is called delegation.

Visibility:
The child class loaders can see the classes loaded by the parent class loaders but the vice-verse is not true.

Uniqueness:
According to principle the classes loaded be parent should not be loaded by the child. Force loading causes the exception.

Building a Simple Class Loader


As i mentioned before custom class loaders can be built by sub classing with java.lang.ClassLoader and overwriting some of the abstract methods. Before going to the code, we will see the explanation for these methods.

loadClass()
This is the only method which need to be overwritten.

Syntax: loadClass(String name, boolean resolvIt)
name - name of the class to loaded
resolveit - if set to true, all the reference classes should be loaded.

Loads the class by the name given. If resolveit is set to true prepares the class with all the references.

defineClass()
This method is final method which cant be overwritten. It will take the raw bytes of data either from network or local file system and turns that into an class object.

findSystemClass()
It locates the file from the local file system .If it can locate the specified file, then  it calls the defineClass to convert the raw bytes to class object.

findLoadedClass()
If the class is already been loaded then that will be cached by this method. Before making any feature requests of loadClass, this method will be called to check the class from cache.

Putting it all together

  1. First JVM request for the class

  2. The current class loader's loadClass will be called.  And it will take care the further processes.

  3. The loadClass() method calls the findLoadedClass() method to check if it is available on the cache.

  4. If it is found it will return the class. Otherwise it uses the delegation and passes the request to it's parent.

  5. If it is found by any of the parent's then it will be returned by the parent's class loader. Otherwise findSystemClass() will be called and it will attempts to locate the file from the local file system.

  6. If the file is found it will be passed to defineClass() which constructs the class object and it will be returned to JVM.

  7. Otherwise ClassNotFoundException will be thrown.


The below figure depicts this flow. This is not the accurate picture but rough flow.

Java Class Loader

 

Sample Code


MyClassLoader.java

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class MyClassloader extends ClassLoader {
private byte[] getBytes(String filename) throws IOException {
File file = new File(filename);
long len = file.length();
byte raw[] = new byte[(int) len];
FileInputStream fin = new FileInputStream(file);
int r = fin.read(raw);
if (r != len)
throw new IOException("Cant read the file");
fin.close();
return raw;
}
public Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Class finalClass = null;
finalClass = findLoadedClass(name);
String classFilename = name + ".class";
try {
byte raw[] = getBytes(classFilename);
finalClass = defineClass(name, raw, 0, raw.length);
} catch (IOException ie) {
}
if (finalClass == null) {
finalClass = findSystemClass(name);
}
if (resolve && finalClass != null)
resolveClass(finalClass);
if (finalClass == null)
throw new ClassNotFoundException(name);
return finalClass;
}
}

ClassLoaderTest.java

import java.lang.reflect.Method;
public class ClassLoaderTest {
public static void main(String args[])throws Exception{
MyClassloader classloader= new MyClassloader();
String progClass = args[0];
String progArgs[] = new String[args.length - 1];
System.arraycopy(args, 1, progArgs, 0, progArgs.length);
Class clas = classloader.loadClass(progClass,true);
Class mainArgType[] = { (new String[0]).getClass() };
Method main = clas.getMethod("main", mainArgType);
Object argsArray[] = { progArgs };
main.invoke(null, argsArray);
}
}

Animal.Java

public class Animal {
static public void main(String args[])throws Exception {
System.out.println("Called animal by the class loader"+ Animal.class.getClassLoader());
}
}

Compilation Steps
javac -cp . Animal.java

javac -cp . MyClassloader.java

javac -cp . ClassLoaderTest.java

Run

java -cp . ClassLoaderTest Animal

Output:

Called animal by the class loader MyClassloader@422ede

From the output we can see, the animal class is loaded by the MyclassLoader.

No comments:

Post a Comment