Java ClassLoader Under the Hoods

ClassLoader: Loading JAVA classes into JVM

Introduction

ClassLoading process in JVM helps to convert Java Class to Java Object, and this is achieved by dynamic loading, linking, and initialization.

Loading: Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation. This results in construction in the method area of the Java Virtual Machine of an internal representation of Class

Linking: Linking is the process of taking a class/ interface and make it ready to be executed by JVM, note that Linking can throw OutOfMemmory error.

  • Linking involves
    • verification: ensures the Class is properly formed and fit for use by the Java virtual machine
    • preparation: involves allocating memory such as memory for any class variables(Static variables). 
    • resolution: is the process of transforming symbolic references(strings that can be used to retrieve the actual object) in the constant pool into direct references.

Initialization: Initialization of a class or interface consists of executing the class or interface initialization method, also class variables are given their proper initial values.

Entry Exit of JVM

  • The Java Virtual Machine starts up by creating an initial class, which is specified in an implementation-dependent manner, using the bootstrap class loader. The Java Virtual Machine then links the initial class, initializes it, and invokes the public class method void main(String[])
  • The Java Virtual Machine exits when some thread invokes the exit method of class Runtime or class System, or the halt method of class Runtime, and the exit or halt operation is permitted by the security manager.

Different Types Of ClassLoders

  • There are two kinds of class loaders:
    • Bootstrap class loader : Loads Java core lib and is parent of all classLoaders. This is written In Machine code and is inside JVM.
    • User-defined class loader : is an instance of a subclass of the abstract class ClassLoader. Applications employ user-defined class loaders in order to extend the manner in which the Java Virtual Machine dynamically loads and thereby creates classes. User-defined class loaders can be used to create classes that originate from user-defined sources. For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file.
      • Extension ClassLoader : loads class at $JAVA_HOME/lib/ext
      • System/ Application ClassLoader: Loads application classes that developers write from the worskspace.

Abstract Class ClassLoader

The java class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a “class file” of that name from a file system.

The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine’s built-in class loader, called the “bootstrap class loader”, does not itself have a parent but may serve as the parent of a ClassLoader instance.


How ClassLoader works internally

  • The left side is the code from the abstract class ClassLoader. When JVM requests for any Class then it invokes the loadClass method in ClassLoader.
  1. FindLoadedClass, Check if the class is already been loaded. When a Class is loaded by this loader it will be stored in Vector Table so as to be used next time it is requested.
  2. ParentLoadClass, As ClassLoader follows a delegation mode, it invokes loadClass on the parent classLoader and delegates parent to find the class. This is done recursively, the Java Library classes are picked from \jre\lib\rt.jar loaded by BootStrap class loader whereas the classes in the workspace wouldn’t be picked from Bootstrap loader and the delegation falls back to ChildLoaders and the classes would be loaded by findClass in AppClassLoader.
  3. FindClass, If the above two fails the ClassLoader itself tried to findClass in the classpath by invoking the method defineClass which causes the Java Virtual Machine to derive a class  from the array of bytes using the different algorithms. An ClassNotFoundException is thrown if Class is still not able to be loaded.
  4. ResolveClass, resolve class involves Linking a class, ie verifying and preparing that class, its direct superclass, its direct superinterfaces such that it gets ready to be executed by JVM.

Create a Custom Class Loader

Let us see how we can create a Custom ClassLoader and load our classes.

Step 1: create Class CustomClassLoader
  • Extend the abstract class ClassLoader
  • Override loadClass Method
  • For our defined packages, we would load using customClass Loader.
    • loadClassFileData : Read the byte code from Java compiled file.
    • defineClass : Converts an array of bytes into an instance of class 
    • resolveClass : Links the specified class

CustomClassLoader.Java

package com.jonesjalapat.classloader;

import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

public class CustomClassLoader extends ClassLoader {
	
	public CustomClassLoader(ClassLoader classLoader) {
		super(classLoader);
	}
	
	/*
	 * 
	 * We are going to load Class from .class file
	 * @param name
	 * @return
	 * @throws ClassNotFoundException
	 */
	 private Class<?> getClass(String name) throws ClassNotFoundException {
	        String file = name.replace('.', File.separatorChar) + ".class";
	        byte[] byteArr = null;
	        try {
	            // This loads the byte code data from the file
	        	byteArr = loadClassFileData(file);
	            // defineClass is inherited from the ClassLoader class
	            // that converts byte array into a Class. defineClass is Final
	            // so we cannot override it
	            Class<?> c = defineClass(name, byteArr, 0, byteArr.length);
	            resolveClass(c);
	            return c;
	        } catch (IOException e) {
	            e.printStackTrace();
	            return null;
	        }
	    }
	 
	    @Override
	    public Class<?> loadClass(String name) throws ClassNotFoundException {
	    	Class<?> clazz = null;
	        if (name.startsWith("com.jonesjalapat.classloader")) {
	            clazz =  getClass(name);
	            System.out.println("Loaded class using " + clazz.getClassLoader() +  " name: " + name);
	            return clazz;
	        } else {
	            clazz = super.loadClass(name);
	            System.out.println("Loaded class using " + clazz.getClassLoader() +  " name: " + name);
		        return clazz;
	        }
	    }
	    
	    private byte[] loadClassFileData(String name) throws IOException {
	        InputStream stream = getClass().getClassLoader().getResourceAsStream(
	                name);
	        int size = stream.available();
	        byte buff[] = new byte[size];
	        DataInputStream in = new DataInputStream(stream);
	        in.readFully(buff);
	        in.close();
	        return buff;
	    }

}

Step 2 : create a utility class which our Custom Loader will load
package com.jonesjalapat.classloader;

import com.jonesjalapat.utils.Civic;

public class Utility {

	public static void print() {
		System.out.println("Utility print method completed ");
	}
	
//	public static void main() {
//		System.out.println("Utility main method ivoked ");
//		new Civic().model();
//		System.out.println("=====Utility main method completed====");
//
//		
//	}

}

Step 3 : create a Test class to invoke our method
package com.jonesjalapat.classloader;

import java.lang.reflect.Method;


public class ClassLoaderTest {
	
    public static void main(String args[]) throws Exception {

        CustomClassLoader ccl = new CustomClassLoader(CustomClassLoader.class.getClassLoader());
        System.out.println("===== Inside Main ClassLoaderTest=====");
        Class<?> clazz = ccl.loadClass("com.jonesjalapat.classloader.Utility");        
        Object ob = clazz.getDeclaredConstructor().newInstance();
        Method md1 = clazz.getMethod("print");
        md1.invoke(ob);
        // Method md2 = clazz.getMethod("main");
        // md2.invoke(ob);
    }

}

Output

The output obtained after running ClassLoaderTest

Before CustomClassLoader is called for loading Utility class, Object is loaded by Bootstrap loader which is seen in console. After that, we invoke the print method which loads System and PrintStream.

Understanding the Sequence in which Java Class is loaded

  • The Order of output in which different components of Class loaded are
    • Static block of parent then child
    • Non static block and constructor of parent then child
    • methods that is invoked

Create three classes Vehicle.java, Honda.java, Civic.java.

Step 1: Create a Civic.java file
package com.jonesjalapat.utils;


class Vehicle {
	
	static {
		System.out.println("####1####");
	}

	{System.out.println("####4####");}
    
	public Vehicle(){
		System.out.println("####5####");
	}

}
class Honda extends Vehicle{
	
	public Honda(){
		System.out.println("####7####");
	}
	
	{System.out.println("####6####");}
	
	static {
		System.out.println("####2####");
	}

}
public class Civic extends Honda {
	
	static {
		System.out.println("####3####");
	}
	
	public Civic() {
		System.out.println("####9####");
	}
	
	{System.out.println("####8####");}
	
    public void model() {
    	System.out.println("####10####");
    }
   
    
}

Output

The output obtained after running ClassLoaderTest and uncomment the commented code.

The order followed is first super Class, then static blocks in super, child static blocks, followed by Non-static blocks and constructor in super, and finally the method that is invoked.

References

2 thoughts on “Java ClassLoader Under the Hoods”

Leave a Comment

Your email address will not be published.

error: Content is protected !!
Scroll to Top