Class Loaders and the Parent-Delegation Model a

How the Java Launcher Finds Classes

The Java launcher, java, initiates the Java virtual machine. The virtual machine searches for and loads classes in this order:

  • Bootstrap classes – Classes that comprise the Java platform, including the classes in rt.jar and several other important jar files. Bootstrap classes are in the rt.jar and several other jar files in the jre/lib directory.
  • Extension classes – Classes that use the Java Extension mechanism. These are bundled as .jar files located in the extensions directory.Extension classes are classes which extend the Java platform: .jar file in the extension directory, jre/lib/ext
  • User classes – Classes defined by developers and third parties that do not take advantage of the extension mechanism. You identify the location of these classes using the -classpath option on the command line (the preferred method) or by using the CLASSPATH environment variable.To find user classes, the launcher refers to the user class path — a list of directories, JAR archives, and ZIP archives which contain class files.

More about how to find these classes 

Now let’s get our hands dirty with some real code. Consider the following example: class A instantiates class B.

	public class A {
	  public void doSomething() {
  	 B b = new B();
   	 b.doSomethingElse();
	  }
	}

The statement B b = new B() is semantically equivalent to B b = A.class.getClassLoader().loadClass(“B”).newInstance()

To better visualize the parent-delegation model, imagine a Java application creates a user-defined class loader named “Grandma.” Because the application passesnull to Grandma’s constructor, Grandma’s parent is set to the bootstrap class loader. Time passes. Sometime later, the application creates another class loader named “Mom.” Because the application passes to Mom’s constructor a reference to Grandma, Mom’s parent is set to the user-defined class loader referred to affectionately as Grandma. More time passes. At some later time, the application creates a class loader named, “Cindy.” Because the application passes to Cindy’s constructor a reference to Mom, Cindy’s parent is set to the user- defined class loader referred to as Mom.

Now imagine the application asks Cindy to load a type named java.io.FileReader. When a class that follows the parent delegation model loads a type, it first delegates to its parent — it asks its parent to try and load the type. Its parent, in turn, asks its parent, which first asks its parent, and so on. The delegation continues all the way up to the end-point of the parent-delegation chain, which is usually the bootstrap class loader. Thus, the first thing Cindy does is ask Mom to load the type. The first thing Mom does is ask Grandma to load the type. And the first thing Grandma does is ask the bootstrap class loader to load the type. In this case, the bootstrap class loader is able to load (or already has loaded) the type, and returns the Class instance representing java.io.FileReader to Grandma. Grandma passes this Class reference back to Mom, who passes it back to Cindy, who returns it to the application.

Note that given delegation between class loaders, the class loader that initiates loading is not necessarily the class loader that actually defines the type. In the previous example, the application initially asked Cindy to load the type, but ultimately, the bootstrap class loader defined the type. In Java terminology, a class loader that is asked to load a type, but returns a type loaded by some other class loader, is called an initiating class loader of that type. The class loader that actually defines the type is called the defining class loader for the type. In the previous example, therefore, the defining class loader for java.io.FileReader is the bootstrap class loader. Class Cindy is an initiating class loader, but so are Mom, Grandma, and even the bootstrap class loader. Any class loader that is asked to load a type and is able to return a reference to the Class instance representing the type is an initiating loader of that type.

For another example, imagine the application asks Cindy to load a type named com.artima.knitting.QuiltPattern. Cindy delegates to Mom, who delegates to Grandma, who delegates to the bootstrap class loader. In this case, however, the bootstrap class loader is unable to load the type. So control returns back to Grandma, who attempts to load the type in her custom way. Because Grandma is responsible for loading standard extensions, and the com.artima.knitting package is wisely installed in a JAR file in the standard extensions directory, Grandma is able to load the type. Grandma defines the type and returns the Class instance representing com.artima.knitting.QuiltPattern to Mom. Mom passes this Class reference back to Cindy, who returns it to the application. In this example, Grandma is the defining loader of the com.artima.knitting.QuiltPattern type. Cindy, Mom, and Grandma — but not the bootstrap class loader — are initiating class loaders for the type.

Note: We can always create our own classLoader and override the loadClass implementation to bypass the default system class loader though it is not recommended for security reasons(meaning we should delegate to bootstrap-classloader first). If we are in container, it is not easy since it always searches the bootstrap class loader first, then the local app lib, then the container lib. More detail in my other post.

ClassCastException

Let’s demonstrate a case for ClassCastException. We’ll modify the initial example to use a factory in order to provide the implementation of a class that provides the greeting message. Sounds contrived but this is quite a common pattern.

public class HelloServlet extends HttpServlet {
   protected void doGet(HttpServletRequest request, 
                                    HttpServletResponse response) 
                                    throws ServletException, IOException {
       PrintWriter out = response.getWriter();
    out.print(((Util)Factory.getUtil()).sayHello());
}
 
class Factory {
     public static Object getUtil() {
          return new Util();
     }
}

The possible result of the request is the unexpected ClassCastException:

java.lang.ClassCastException: Util cannot be cast to Util
	HelloServlet:doGet(HelloServlet.java:18)
	javax.servlet.http.HttpServlet.service(HttpServlet.			java:617)
	javax.servlet.http.HttpServlet.service(HttpServlet.			java:717)

It means that HelloServlet and Factory classes operate in different context. We have to figure out how these classes were loaded. Let’s use -verbose:class and figure out how the Util class was loaded in regards to HelloServlet and Factory classes.

[Loaded Util from file:/Users/ekabanov/Applications/ apache-tomcat-6.0.20/lib/cl-shared-jar.jar]
[Loaded Util from file:/Users/ekabanov/Documents/workspace-javazone/.metadata/.plugins/org.eclipse.wst. server.core/tmp0/wtpwebapps/cl-demo/WEB-INF/lib/cl-demo- jar.jar]

So the Util class is loaded from two different locations by different classloaders. One is in the web application classloader and the other in the application container classloader.

But why are they incompatible? Turns out that originally every class in Java was identified uniquely by its fully qualified name. But in 1997 a paper was published that exposed an expansive security issue cause by this–namely, it was possible for a sandboxed application (i.e. applet) to define any class includingjava.lang.String and inject its own code outside the sandbox.

The solution was to identify the class by a combination of the fully qualified name and the classloader! It means that Util class loaded from classloader A and Util class loaded from classloader B are different classes as far as the JVM is concerned and one cannot be cast to the other!

The root of this problem is the reversed behavior of the web classloader. If the web classloader would behave in the same way as the other classloaders, then the Util class would have been loaded once from the application container classloader and no ClassCastException would be thrown.

The above example is from this very good article on classloader And below is the pdf version of it.

do-you-really-get-classloaders

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s