Wednesday 28 May 2014

Java Class Loading Mechanism

Java Class Loading Mechanism



Class loading is one of the most powerful mechanisms provided by the Java language specification.

Whenever we compile any Java file, the compiler will embed a public, static, final field named class, of the type java.lang.Class, in the resultant byte code. Since this field is static, we can access this field using class name like this:
                  
   Java.lang.Class kClass = MyClass.class;

When the run time environment needs to load a new class for an application, it looks for the class in the following locations, in order:

1.  Bootstrap classes:  the runtime classes in rt.jar, internationalization classes in                      i18n.jar, and   others. 

2.  Installed extensions :  classes in JAR files in the lib/ext directory of the JRE

3. The class path : classes, including classes in JAR files, on paths specified by the system          property java.class.path

The precedence list tells you, for example, that the class path is searched only if a class to be loaded hasn't been found among the classes in rt.jar, i18n.jar or the installed extensions.

The class in java is loaded by some class loader instance. How class loader works? Once a class is loaded in JVM, the same class will not be loaded again. How?

In Java, a class is identified by its fully qualified class name. The fully qualified class name consists of the package name and the class name. But in JVM, a class is uniquely identified using fully qualified class name along with the instance of the ClassLoader that loaded the class in JVM.
Thus, if a class named Cl in the package Pkg is loaded by an instance kl1 of the class loader KlassLoader, the class instance (java.lang.Class instance inserted by compiler) of C1, i.e. C1.class is keyed in the JVM as (Cl, Pkg, kl1). So what if multiple instances (Kl1, Kl2, Kl3) of class Loader say KlassLoader, loads the same class? How many class loader instances do we have in a JVM? This is explained below.

Class Loaders

In a JVM, each and every class is loaded by some instance of java.lang.ClassLoader class. The ClassLoader is part of java.lang package and developers are free to subclass java.lang.ClassLoader class and add their own functionality of class loading. When the JVM is started, three class loaders are used:

 1.  Bootstrap class Loader

      Whenever a JVM is started by typing command in command prompt like “java MyClass” (MyClass is an example class) or whenever class is run through any IDE, the “Bootstrap class loader” is responsible for loading the key classes like “java.lang.Object” and other runtime code (java.lang.String, java.lang.* pkg etc)  packaged in to jre/lib/rt.jar, internationalization classes in i18n.jar into memory first.  rt.jar contains packages like :

java.lang.*,
java.math.*,
java.io.*,
java.sql.*,
java.nio.*,
java.awt.*,
java.rmi.*,
javax.annotation.*,
javax.lang. model.*
javax.rmi.*
etc.

Bootstrap class loader is a native implementation and thus the behavior of the bootstrap class loader will also vary across JVMs. 

If we try to get the class loader of the core java run time class like java.lang.String, we will get null, like this:   log (java.lang.String.class.getClassLoader());


2.Extension class loader:


Extension libraries provide features beyond core Java run time code. The extension mechanism provides a standard, scalable way to make custom APIs available to all applications running on the Java platform.

An extension library acts as “add-on” modules to the Java platform or Java core API.  The extension mechanism enables the run time environment to find and load extension classes without the extension classes having to be named on the class path. These extension libraries are normally placed in jre/lib/ext folder.

Developers can write their own extension libraries and can place these libraries under jre/lib/ext folder and these libraries are loaded same as java runtime classes without using class path.  Since this mechanism extends the platform's core API, its use should be judiciously applied.
 

                                                                      

Thus extension libraries provide features beyond the core Java runtime code. A developer can add his or her own application .jar files or whatever libraries he or she might need to add to the classpath to this extension directory so that they will be loaded by the extension class loader.

Thus extension class loader (ExtClassLoader class) is responsible for loading all .jar files under ext (most probably jre/lib/ext) folder.

3. Application Class Loader

The third and most important class loader from the developer perspective is the AppClassLoader. The application class loader is responsible for loading all of the classes kept in the class path corresponding to the java.class.path system property.

Above three class loaders are used mostly.  There are few more class loaders in JDL like:
  java.net.URLClassLoader
  java.security.SecureClassLoader
  java.rmi.server.RMIClassLoader
  sun.applet.AppletClassLoader


How class Loaders work:

Below points are very important for the correct working of any class loader written by developers:-

1. All class loaders except bootstrap class loader have a parent class loader.
2. All class loaders are of the type java.lang.ClassLoader.
3. Class loaders should (practically: must) delegate the loading of a class to the parent, but a custom class loader can define for itself when it should do so.
4. A class is defined by its class type and the class loader that has actually loaded the class.
5. A class is only loaded once and then cached in the class loader to ensure that the byte code cannot change.

The parent class loader for any class loader is the class loader instance that loaded the class loader. (Remember, a class loader is itself a class). The most important aspect is to correctly set the parent class loader. See below code snippet to set the parent class loader in a developer written class loader.

public class MyClassLoader extends ClassLoader{

    public MyClassLoader(){
        super(MyClassLoader.class.getClassLoader());
    }

}

A class is requested out of class loader using the loadClass() method of java.lang.ClassLoader class. Look below code snippet of loadClass() method.

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
    // First check if the class is already loaded
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClass0(name);
            }
        } catch (ClassNotFoundException e) {
            // If still not found, then invoke
            // findClass to find the class.
            c = findClass(name);
        }
    }
    if (resolve) {
            resolveClass(c);
    }
    return c;
}

  1. This method first checks if class is already loaded using findLoadedClass() method.

22.  If class loader instance that invoked this method can’t find the class, and if parent (parent class loader) is set correctly, it would ask the parent class loader first to load the class.

33.  If the parent cannot find it (which again means that its parent also cannot find the class, and so on), and if the findBootstrapClass0() method also fails, the findClass() method is invoked. The default implementation of findClass() will throw ClassNotFoundException  as shown below:

protected Class<?> findClass(String name)throws ClassNotFoundException
{
        throw new ClassNotFoundException(name);
      } 

4. Developers are expected to implement findClass() method when they subclass  java.lang.ClassLoader to make custom class loader. Inside the findClass() method, the class  loader needs to fetch the byte codes from arbitrary source. The source can be the file  system,database, network URL etc. 

   5.  Once the byte code is retrieved, the findClass() method should call the defineClass() method     and runtime is very particular about which class loader instance calls this method.

Note: If two class loader instances define the byte codes from same or different sources, the defined classes are different.  


Below diagram explains the class loading mechanism using custom class loaders, how many class loader instances we have in JVM and what would be the impact of multiple instances of class loaders.    

      

                                               

 
Explanation:--     

1. Main class is MyMainClass.Java

2. As explained earlier, MyMainClass.class will be loaded by AppClassLoader as                           AppClassLoader is responsible for loading classes from class path.

3. MyMainClass creates instances of two class loaders, CustomClassLoader1 and CustomClassLoader2, which are capable of finding the byte code of 4th class named Target.class from some source say a network path, which means Target.Java is not in the classpath and hence is not loaded by AppClassLoader.

4.   In this scenario, MyMainClass asks the custom class loaders to load the target class, Target will be loaded and Target.class will be defined independently by both CustomClassLoader1 and CustomClassLoader2 instances and this will lead to serious implications in Java like if Target class has some static initialization code and if we want this code to be executed only once in JVM, but in current scenario the static code will be executed twice in the JVM: once each when class is loaded separately by both custom class loaders CustomClassLoader1 and CustomClassLoader2 .

5.  If the Target class is instantiated in both the CustomClassLoaders to have instances target1 and target2 as shown in above figure, then target1 and target2 are not type compatible. JVM can’t  execute the below code snippet:

Target target3 = (Target) target2;
                This will throw ClassCastException because JVM sees these two as separate, distinct class types since they are defined by different class loader instances.


The above explanation holds true even if MyMainClass doesn't use two separate class loader classes like CustomClassLoader1 and CustomClassLoader2, and instead uses two separate instances of a single CustomClassLoader class.


With above we can conclude, In JVM we have single class loader instance to load the class.

2 comments: