Tomcat Classloader Demonstration

By | 二月 14, 2012

In a J2SE 2 (that is, J2SE 1.2 or later) environment, class loaders are arranged in a parent-child tree. Normally, when a class loader is asked to load a particular class or resource, it delegates the request to a parent class loader first, and then looks in its own repositories only if the parent class loader(s) cannot find the requested class or resource. The model for web application class loaders differs slightly from this.

About java class loading, the primary concepts are:

  1. class files located in both parent and child classloader’s repository, the former will be loaded;
  2. classes loaded by parent classloader are visible to all child classloader, the reverse is *not* true.

Again, Tomcat’s Web application classloader deffers slightly from this.

From tomcat5.5 to 6.0, there are some changes to tomcat classloader hierarchy as shown below.

Tomcat5.5 ClassLoader hierarchy Tomcat7 ClassLoader hierarchy

The left picture shows the classloader hierarchy of Tomcat5.5 and right one is for Tomcat6+. Catalina and Shared these two classloaders had been removed, the classes loaded by these two now are loaded by Common classloader which is [org.apache.catalina.loader.StandardClassLoader].

The demo will create three servlets and put them into $catalina_base/lib, $catalina_base/shared and web applications WEB-INF/classes folder respectively. All of them will print their class loader while being loaded and will be initialized when application been deployed.

[CommonServlet]

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

public class CommonServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	static {
		System.out.println("CommonServlet Loaded by ["
				+ CommonServlet.class.getClassLoader() + "]");
	}

	public void init() throws ServletException {
		Echo.echo(getServletName());
	}

}

This will be put into $catalina_base/lib.

[WebAppServlet]

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

public class WebAppServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	static {
		System.out.println("WebAppServlet Loaded by ["
				+ WebAppServlet.class.getClassLoader() + "]");
	}

	public void init() throws ServletException {
		Echo.echo(getServletName());
	}

}

This will be put into web application’s WEB-INF/classes folder, the test web application here is “test”.

[SharedServlet]

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

public class SharedServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	static {
		System.out.println("SharedServlet Loaded by ["
				+ SharedServlet.class.getClassLoader() + "]");
	}

	public void init() throws ServletException {
		Echo.echo(getServletName());
	}

}


This will be put into $catalina_base/shared folder, this folder does not exist by default from tomcat6.0. You have to create it and edit $catalina_home/conf/catalina.properties as below

shared.loader=${catalina.base}/shared


Lastly, [Echo]

public class Echo {

	static {
		System.out.println("Echo loaded by [" + Echo.class.getClassLoader()
				+ "]");
	}

	public static void echo(String from) {
		System.out.println("Echo from [" + from + "]");
	}

}


I’ve put this class to each of above three folders. Now start the tomcat, see what happens.

WebAppServlet Loaded by [WebappClassLoader
  context: /test
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@1ee29820]
Echo loaded by [WebappClassLoader
  context: /test
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@1ee29820]
Echo from [WebAppServlet]
CommonServlet Loaded by [org.apache.catalina.loader.StandardClassLoader@1f5b0afd]
Echo loaded by [org.apache.catalina.loader.StandardClassLoader@1f5b0afd]
Echo from [CommonServlet]
SharedServlet Loaded by [org.apache.catalina.loader.StandardClassLoader@1ee29820]
Echo from [SharedServlet]

First the WebAppServlet is loaded by WebappClassLoader, whose parent classloader is StandardClassLoader. Then it requires Echo class, the normal process should be ask it’s parent class loader to load the Echo class (Echo.class do exist in the parent classloader’s repository), but it’s not. That is what “deffers slightly” means at beginning of this post. Before delegate to its parent classloader, tomcat’s web app classloader will look up its repository first. Hence, Echo.class located in the WEB-INF/classes been loaded by WebappClassLoader.

Next, CommonServlet loaded by common classloader(StandardClassLoader) as expected. Note, here the Echo class been loaded again, that’s because of concept 2 mentioned at the beginning. Classes loaded by parent are visible to child classloader, but reverse is not true.

At last, SharedServlet been loaded by the same common classloader, which approves common classloader covers the duty of shared classloader in Tomcat5.5 and before.

For more info about tomcat’s classloader, see ClassLoader How-to.

2 thoughts on “Tomcat Classloader Demonstration

  1. Pingback: The Best Skin Care Products For African American Women!_led flood lighting | Prom Runway

  2. Marcos Vickrey

    Just want to say your article is as surprising. The clarity in your submit is just great and that i can suppose you are a professional in this subject. Fine with your permission let me to snatch your RSS feed to keep up to date with impending post. Thanks a million and please carry on the gratifying work.

    Reply

发表评论

电子邮件地址不会被公开。 必填项已用*标注