Thursday, December 20, 2012

The Class Loader Subsystem


The Class Loader is one of the key components of Java, All modern day java containers [EJB, Servlet,..] has custom class loaders. An in-depth understanding of class loaders is required for developing, debugging, packaging, deployment and better architecture of J2EE components.

As Wikipedia says, "The Java Classloader is a part of the Java Runtime Environment that dynamically loads Java classes into the Java Virtual Machine". It is as simple as that! 

Now, even before we look into how class loader works, it is important to understand what loading a class means? 

A class has to go through three phases in order to get loaded in to the JVM, they are Loading, Linking and Initialization.


The Java Specifications mandates that the Initialization phase should happen only when the Class gets its first active usage whereas Loading & Linking phases can vary from JVM to JVM. Most of the JVM loading happens much earlier whereas the linking and initializing will be delayed till the first use.

By delaying the Initialization phase, the class loading is delayed until the class is referred/required [using new, static reference, etc.] thus reducing memory usage and improving system response time. 


Irrespective of when the loading, linking or initializing happens, any error occurred during these phases will be captured in the form of Linkage Error and thrown only at its first usage of that class. 

The Class Loader is responsible for doing all these three phases, now let's see how Class Loader functions.

Almost all Class loader subsystem has minimum of three class loaders in it; in addition to that we can write our own class loaders. Almost all java programs/containers will relay on the class loaders delegation hierarchy to load their classes into JVM.



Bootstrap or Primordial Class loader: This is responsible for loading only the core Java API (e.g. classes files from rt.jar).  This is the only class loader, which comes with JVM implementation [Mostly written in C, C++]. This is root of all the class loader hierarchy.

Extension Class loader: Responsible for loading classes from the Java extension directory (i.e. classes or jars in jre/lib/ext of the java installation directory). Bootstrap is the parent of this class loader.

System class loader or Application class loader: Responsible for loading classes from the java class path [class directories, jars from class path]. Extension class loader is the parent of this class loader. This class loader is by default the parent of all the custom/user defined class loaders in a java application.


The Bootstrap class loader is the primordial class loader comes with JVM implementation, rest of the class loaders are just like any other java objects.

Consider the below example: We are trying to find the class loader responsible for loading three classes, where the MyConstant.class is placed in ././ jre/lib/ext directory as well as in local workspace and DemoTest is the main class from local workspace


The output will be something like this

Where:
ExtensionClassLoader  loads MyConstant class from ext directory
ApplicationClassLoader loads DemoTest  class from local workspace 
BootStrapClassLoader loads String class but it is null because it is not a java object

But we know that MyConstant class is there in the ext directory as well as the local workspace then why does the AppClassLoader didn’t load the class?

To understand this we need to be aware of the Class Loader Algorithm, which is based on Delegation Hierarchy Principle:

  1. The current class loaders checks whether the class is already loaded, if so return it 
  2. If class is not already loaded, it delegates the work of loading classes to their parent. This delegation can go up to BootStrapClassLoader 
  3. If the parent classloader cannot find the class, then the current classloader attempt to find them locally.
  4. If the class is not found then java.lang.ClassNotFoundException will be thrown

In our case, when
String class is referred - the AppClassLoader delegates the request to its parent ExtClassLoader, which in turn delegates the request to its parent BootStrapClassLoader. The Bootstrap class loader finds the class from java.lang package and returns it back

MyConstant class is referred - the ApplicationClassLoader delegates the request to its parent ExtClassLoader, which in turn delegates the request to BootStrapClassLoader; since MyConstant is not part of java api jars BootStrapClassLoader fails to find the class so the request comes back to ExtensionClassLoader, and since MyConstant class is available in ext directory, the ExtensionClassLoader loads the class.

That’s why the MyConstant was not loaded from local classpath; instead ExtClassLoader loaded it from ext directory.

Every class will be loaded only once by a class loader, there could be chances where a same class might get loaded by different class loaders, which is covered in the Class Loading Errors and Suggestion section.

With this, Assume when we are packaging a war file having its own libraries, say log4j jar [version x] whereas the servlet container [server] has its own library  [log4j jar version y]. 

In this case, we want our application [war] to load your library classes [log4j of version x] and not the container’s. How it is achieved?  

Java EE Delegation Hierarchy:

In general almost all container will have its own class loader to load their libraries.
Also every WAR/EAR has its own class loader as well. 

The Java Servlet specification recommends [does not force] the war classloader should load the class even before it delegate to its parent i.e., container class loader. Container class loader will work in the normal way, it delegates to system, extension and bootstrap classloader.




Most of the application container this recommendation is followed, in container like GlassFish we will be able to configure on which delegation model to be followed.

With this I hope you would have got some basic understanding on class loader. Before we complete I would also want to let you know about few of the class loading error, which you would have seen very often

Class Loading Errors and Suggestions

ClassNotFoundException: This occurs when we try to load the class dynamically [Class.forName() or ClassLoader.loadClass() - where the class name is passed as String] and the class is not found. This is a Checked Exception and caller can perform any corrective action.

NoClassFoundError : This error occurs a class is directly referred [new or ClassName] in the code is not found. This comes under LinkageError, it occur's in the first phase of class loading life cycle.

ClassCastException: This exception occurs in two cases
  1. When we try to cast object of two different incompatible types, which can be solved easily
  2. When more than one class loader loaded the same class and casting between them [casting of object of same type loaded by different classloader]
Assume there is an EAR package, consisting of a WAR, and its library files [say lib1.jar, lib2.jar]. The WAR package in turn has its own library say [the same lib2.jar]

A java class from WAR package calls a method from lib1.jar say DemoHelper.getDemo() [available in EAR package], and that method returns a object from lib2.jar [say Demo] and it is casted to Demo.  Something similar to below code snippet


Now the class cast exception will be thrown because the Demo class loaded by the WAR class loader is different from the Demo class loaded by EAR Class loader.

Just to reiterate the JavaEEContainer Delegation hierarchy, the WAR/EAR classloader will try to load the required class before it delegate to its parent.

In our case, when Demo is referred in EAR jar, the EAR classloader loads the Demo class from its library, and when Demo class is referred from WAR class [casting], the WAR classloader tries to loads the class from its library and it finds one but it is different from the only returned from the other class loader hence the error occurred. 

Incase the WAR classloader couldn't find  the Demo class [lib2.jar is not there in WAR], then the request would have delegated to its parent class loader, i.e. EAR class loader and which would have returned the already loaded Demo class hence this issue could have avoided.

To Summarize:
  1. Class loaders are a powerful mechanism for dynamically loading software components on the Java platform
  2. Every loaded class has an instance of the java.lang.Class object in the heap
  3. Any class will be loaded only once by a class loader hierarchy
  4. In general every class loader delegates the class load requests to its parent before trying to load the class on its own
  5. Avoid using duplicated libraries, a good understanding of class loaders is required for packaging, deployment of J2EE components
There are much more on class loading, reloading, Hence requesting the readers to continue exploring. Below are some of the articles on Class Loaders.

http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html
http://www.artima.com/insidejvm/ed2/lifetype.html
http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html#dynamicloading
http://geekexplains.blogspot.in/2008/07/loading-linking-initialization-of-types.html
http://zeroturnaround.com/labs/rebel-labs-tutorial-do-you-really-get-classloaders/
http://javapapers.com/core-java/java-class-loader/
http://java.sys-con.com/node/37659
http://developeriq.in/articles/2007/oct/03/java-class-loader-class-apart/
http://onjava.com/pub/a/onjava/2005/01/26/classloading.html