Tomcat's class loading can be tricky some times. If you search on class loading problems, you'll find myriads of posts on blogs, forums, etc. And it's not just because people don't know how it works (which is actually
well documented), but because it sometimes doesn't work.

There've been bugs in Tomcat's class loading and even if it's working as expected, it can give you a hard time to track down what's actually happening behind the scene.
Debugging is easier, than you'd think. Tomcat's code already contains (almost) all the debug logging that you need ... you just have to enable the proper logging. This is (again)
well documented.
If you're a developer, chances are high that you've quite a couple of webapps in your Tomcat directory. Enabling debug logging would create huge logfiles so I suggest that you download a fresh copy of Tomcat and create a clean test suite for tracking down your class loading issues.
You should follow the
logging configuration guide to set up logging of the
org.apache.catalina.loader package for the
DEBUG level. This will contain log of all actions that Tomcat takes to load you webapp (and all the JARs in your webapp's
WEB-INF/lib directory) and to load the classed required/referenced by you application.
Here're the main steps (for the 5.5 branch):
- Download the latest available version and unpack it.
- Copy your webapp to the
$CATALINA_HOME/webapps directory.
- Download the JAR for log4j and place it in
$CATALINA_HOME/common/lib.
- Download the JAR for commons-logging and place it in
$CATALINA_HOME/common/lib as well.
- Create a
log4j.properties file in $CATALINA_HOME/common/classes with something like this as the content:
log4j.rootLogger=WARN, R
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=${catalina.home}/logs/tomcat.log
log4j.appender.R.MaxFileSize=10MB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
log4j.appender.Loaders=org.apache.log4j.RollingFileAppender
log4j.appender.Loaders.File=${catalina.home}/logs/loaders.log
log4j.appender.Loaders.MaxFileSize=10MB
log4j.appender.Loaders.MaxBackupIndex=10
log4j.appender.Loaders.layout=org.apache.log4j.PatternLayout
log4j.appender.Loaders.layout.ConversionPattern=%p %t %c - %m%n
log4j.logger.org.apache.catalina.loader=ALL, Loaders
- Set the
JAVA_HOME variable to point to the JDK directory.
- Start Tomcat with
bin/startup.sh (or bin/startup.bat in case of Windows)
You should find all ClassLoader logs in the
$CATALINA_HOME/logs/loaders.log file. Look for the lines with the
"addJar" string (generated by the
WebappClassLoader class) since they'll tell you the order in which JARs were discovered/loaded. Look for the lines with the
"loadClass" string since they'll tell you which classloader was used to define a requested class.
These logs are enough to tell which class is loaded from exactly which JAR. One thing you should now: if a class is present in multiple JARs in the same directory, then the class is taken from the first JAR (in the order the JARs were discovered).
P.S.: you might want to clean up the
$CATALINA_HOME/webapps directory (since it contains a number of webapps by default) to save even more on logfile size (and thus make the logs easier to read/use).
Comments
Excellent post indeed