Monday, January 5, 2009

Tomcat 6 and class loading

In continuation with the previous blog entry, I would also like to write about Tomcat 6 (in particular) and class loading pattern that it adopts. Java allows the creation of custom class loaders by implementing the java.lang.ClassLoader. Now Tomcat 6 creates the following class loaders on startup. They share a parent-child relationship too, but NOTE that the delegation pattern is a bit different as will be explained

Although invisible in default installation of Tomcat 6, there are additional shared and server class loaders also available and they fall below the Common class loader in the hierarchy. Each of the class loaders has a responsibility to load classes from certain specific areas, noted below:  

1. Bootstrap + Extension class loader - It loads the Java run-time classes in the JDK as well as any classes from the jars in the Extensions folder.  

2. System class loader - As noted in the previous blog, the System class loader is responsible for loading the classes and the Jar classes present in the CLASSPATH. But an important NOTE here: Tomcat clears the user-set CLASSPATH entry in its startup.bat or startup.sh file. Instead it sets the CLASSPATH to be following: $CATALINA_HOME/bin/bootstrap.jar $CATALINA_HOME/bin/tomcat-juli.jar  

3. Common class loader - This is a Tomcat 6 provided class loader. It loads the classes present in the following folder - $CATALINA_HOME/lib. These classes are available to Tomcat as well as all the web applications that will be hosted on this instance of Tomcat. Although developers can reference the APIs from the jars inside the $CATALINA_HOME/lib directory, they shouldn't be placing their own custom classes and/or jars in there. If developers need certain custom classes and/or jars to be shared by all web applications, then they should be placed where the shared class loader can see them. Note that Tomcat 6.0.14 the $CATALINA_HOME/shared/lib directory does not exist. So this can be done in Tomcat 6 as foll:
  • Create your own $CATALINA_HOME/shared/lib directory.
  • Modify $CATALINA_HOME/conf/catalina.properties by changing the line: shared.loader = ${catalina.home}/shared/lib
However the above does not apply to certain 3rd party libraries such as database drivers etc where Tomcat itself would need to set up data sources. Such jars have to be placed in the $CATALINA_HOME/lib folder for the common class loader to see. One can also add more jars for the common class loader without placing them under the $CATALINA_HOME/lib folder. This can be done by modifying $CATALINA_HOME/conf/catalina.properties by changing the property common.loader as above.  

4. WebappX class loaders - Tomcat creates a class loader for every webapp that is deployed in its instance. This class loader loads classes under WEB-INF/classes and WEB-INF/lib folder. It is for these class loaders where the delegation model deviates, thanks to the Servlet Specification which states as follows: "It is recommended also that the [web] application class loader be implemented so that classes and resources packaged within the WAR are loaded in preference to classes and resources residing in container-wide library JARs."
However the above specification cannot override the Java standard delegation model of delegating to Bootstrap and System class loaders. It only is used to override the parent-child relationships that are introduced by Tomcat - ie. Common, Shared and WebappX class loaders. So when an application requests a class, the class loading hierarchy is as follows:
  1. The bootstrap class loader looks in the core Java classes folders.
  2. The system class loader looks in the $CATALINA_HOME/bin/bootstrap.jar and
  3. $CATALINA_HOME/bin/tomcat-juli.jar
  4. The WebAppX class loader looks in WEB-INF/classes and then WEB-INF/lib
  5. The common class loader looks in $CATALINA_HOME/lib folder.
  6. The shared class loader looks in $CATALINA_HOME/shared/classes and $CATALINA_HOME/shared/lib if the shared.loader property is set in conf/catalina.properties file.

2 comments:

Mohsin Khan said...

how are to make the tomcat web class loader to load the jar file from other location than web-inf/lib folder.

Mayank said...

This was quiet useful.