Tags


Classloader allows JVM to load classes. Regular Java applications running from command line involve three classloaders – Bootstrap, Extensions and System-Classpath classloaders. The three class loaders have a parent child relationship among themselves

1. Classes in the list of bootstrap classes— These are classes that embody the Java platform, such as the classes in rt.jar.

2. Classes that appear in the list of extension classes— These classes use the Extension Mechanism Framework to extend the Java platform, with archive files (.jar, .zip, etc.) located in the /lib/ext directory of the runtime environment.

3. User classes—These are classes that do not use the extension mechanism architecture identified using the -classpath command-line option or the CLASSPATH environment variable.

pic1

 Classloader problems, when they occur are difficult to debug. There are only three basic principles to understand.

Classloader hierarchy illustrating the delegation.

Classloader hierarchy illustrating the delegation.

 The first principle is Delegation Principle. According to this principle, if a particular class is not loaded already, the classloaders delegate the requests to load that class to their parent classloaders. This delegation continues until the top of the hierarchy is reached and the primordial classloader loads the class. The System-ClassPath classloader loads a class called MyApp. MyApp creates a new instance of java.util.Vector. Assume that java.util.Vector has not been loaded already. Since System-Classpath classloader loaded the MyApp class, it first asks its parent, the extension classloader to load the class. The extension classloader asks the Bootstrap classloader to load java.util.Vector. Since java.util.Vector is a J2SE class, the bootstrap classloader loads it and returns. Consider a slightly different scenario. In this case, MyApp creates a new instance of MyClass, another application specific class. Assume that MyClass has not been loaded yet. As usual, when the System-Classpath classloader receives the request to load the class, it delegates it to its parent. The request finally reaches the Bootstrap classloader. It cannot find the class. Hence its child, Extensions classloader tries to load it. It cannot find it either. Finally the request comes back to the System-Classpath classloader. It finds the class and loads it. This explains the alternative path when everything is not a happy day scenario.

 Classloader hierarchy illustrating the delegation when classes cannot be found

Classloader hierarchy illustrating the delegation when classes cannot be found

 

 

 Classloader hierarchy and classes visibility.

Classloader hierarchy and classes visibility.

 The second principle is the Visibility principle. According to this principle, Classes loaded by parent classloaders are visible to child classloaders but not vice versa. What this means is that a class can only see other classes loaded by the ClassX’s classloader or one of its parents. The reverse is not true i.e. a class loaded by ClassX’s parent classloader cannot see ClassX. An example will make things clearer. Look at above figure. Four classloaders are shown- ClassLoaders A, B, X and Y. Class A is the topmost Classloader. ClassLoader B is its child. ClassLoaders X and Y are B’s siblings. Each of them loads classes with same names i.e. A, B, X and Y. A is the only class visible as far as other classes loaded by ClassLoader A are concerned. As far as classes loaded by ClassLoader B is concerned, A and B are the visible classes. Similarly for classes loaded by ClassLoader X, classes A, B and X are visible, but not class Y. Sibling classloaders cannot see each other’s classes.

The third principle is the class Uniqueness Principle. According to this principle, when a classloader loads a class, the child classloaders in the hierarchy will never reload the class. This follows from the delegation principle since a classloader always delegates class loading to its parents. The child classloader will load it (or try to load it) only if the parent hierarchy fails to load the class. Thus the uniqueness of the class is maintained. An interesting scenario emerges when both parent and child classloaders load the same class. You might think how is this feasible after all. Isn’t this contradicting the class uniqueness principle? To answer this question look at figure again. Let us assume that none of the classes have been loaded anywhere in the hierarchy. Let us also suppose that X, loaded by ClassLoader X, forcefully uses its classloader to load B. This can be done as shown in example below by using an API such as Class.forName(). The code shows such a scenario. Using Class.forName() 01 public class X { 02 03 public X() { 04 ClassLoader cl = this.getClass().getClassLoader(); 05 Class B = Class.forName(“B”, true, cl); 06 } 07 } In the constructor for X, the class B is loaded by explicitly using Person’s parent classloader, i.e. the parent of the classloader that loaded Person. By doing so, the delegation is overridden and B is loaded by ClassLoaderX – the classloader of X. Now suppose that another class loaded by ClassLoader B tries to access B, it cannot find it and hence follows the delegation principle. Since the delegation principle only consults the parents, ClassLoader B also eventually loads Class B. When some other code tries to compare two objects of type B – each loaded by different classloaders, it gets a ClassCastException.

About these ads