tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Craig R. McClanahan" <>
Subject Re: Servlet ClassLoader
Date Fri, 02 Feb 2001 17:58:45 GMT
Arthur Ash wrote:

> Hi Folks,
> I'm having a general issue with the app-specific classpath (WEB-INF/classes
> and WEB-INF/lib/*.jar).
> Here is the scenario as I understand it:
> I have an MVC servlet/bean framework that is installed in the primordial
> classpath.  It contains a single dispatcher servlet which instantiates
> handler classes (which function like servlets) using Class.forName().   My
> intention is to to put these app-specific handler classes in
> WEB-INF/classes or WEB-INF/lib in order to be a good J2EE citizen.

The Struts framework <> follows essentially the
same model.  However, due to classloader issues (more discussion below) the
controller servlet class itself must also be in WEB-INF/classes or WEB-INF/lib
for this to work correctly.

> However, since the dispatch servlet has been loaded with the primordial
> class loader (ie, the Tomcat code first tried and succeeded to load it
> using the default class loader), when it itslef calls Class.forName(), it
> gets this same (primordial) ClassLoader.  It cannot see anything that is in
> WEB-INF, since this is visible to only to the servlet class loader (ie,
> com.apache.tomcat.loader.AdaptiveClassLoader).

Class loaders are arranged in a hierarchy.  For Tomcat 4.0, the details are
discussed in a developer document ("catalina/docs/dev/classloaders.html) in the
source tree.  I will use that to illustrate what's going on because I'm more
familiar with it - Tomcat 3.2 currently follows a simplified version of the
same basic idea.

                      /      \
                 Catalina   Shared
                           /     \
                       Webapp1  Webapp2 ...

Each class loader has a reference to its parent, but not to its children.  So,
when your controller servlet is initially loaded (from a shared library
directory), what actually happened is:
* Java asked the webapp class loader to find the
  controller servlet class
* The webapp class loader did not find the class
  so it delegated to the shared class loader
* The shared class loader (which reads from $CATALINA_HOME/lib
  in Tomcat 4.0 -- the corresponding loader in Tomcat 3.2 reads
  from the system classpath) and finds your class

Now, when your controller servlet calls Class.forName(), it starts from its
*own* class loader, and looks either there, or upwards.  Of course, if your
components are under WEB-INF/classes or WEB-INF/lib, they are not visible ...

> Am I just screwed or is there some cool trick that I am missing?  Of course
> I could change the deployment scheme to put a copy of the dispatcher
> servlet into each apps WE-INF/classes, but this seems a bit clunky.

It's not clunky -- its required by virtue of the fact that classloaders know
how to delegate upwards but not downwards.  For lots of security related
reasons, that is actually a Good Thing.

> thanks
> Arthur

Craig McClanahan

View raw message