Like many server applications, Catalina installs a variety of class loaders
(that is, classes that extend java.lang.ClassLoader
) to allow
different portions of the container, and the web applications running on the
container, to have access to different repositories of available classes and
resources. This mechanism is used to provide the functionality defined in
the Servlet API Specification, version 2.3 (public draft 1) -- in particular
sections 9.4 and 9.6.
The remainder of this document provides an overview diagram of the parent - child relationships between each class loader that is created, more detailed information about the content and use of each class loader, and some additional relevant notes.
In a Java2 environment, class loaders are arranged in a parentage tree. Normally, when a class loader is asked to load a class (or get a resource), it delegates the request upwards first, and only searches its local repositories if the parent class loader(s) cannot find the requested class or resource. The model for web applications differs slightly from this, as discussed further below.
The class loaders that Catalina uses are organized as follows, where the parent class loader is above the child class loaders:
Bootstrap | System | Common / \ Catalina Shared / \ Webapp1 Webapp2 ... / / Jasper1 Jasper2
The usage of and repositories contained in each class loader are described further below:
java.*
classes. Depending on how your particular JVM
is organized, this may actually be more than one class loader, or
may not exist at all. It is generally not referenced directly.CLASSPATH
environment variable, and
contains classes that must be visible to both the Catalina internal
classes and to web applications. The standard Catalina startup scripts
assemble the following repositories for the system class path:
$CATALINA_HOME/bin/bootstrap.jar
- The Bootstrap class
that is used to initialize the Catalina server, and the class
loader implementation classes it depends on.$JAVA_HOME/lib/tools.jar
- The Javac
compiler used to compile the servlets generated from JSP pages
(if present on your system).$CATALINA_HOME/common/classes
directory (if it exists), and all JAR files in the
$CATALINA_HOME/common/lib
directory (if it exists). The
latter group normally includes the following:
jndi.jar
- The Java Naming and Directory Service API
classes (loaded only if not already included in
the JDK, as they are with JDK 1.3).naming.jar
- The JNDI implementation used by
Tomcat 4 itself.servlet.jar
- The servlet and JSP API classes.$CATALINA_HOME/server/classes
directory (if it exists), and all JAR files in the
$CATALINA_HOME/server/lib
directory (if it exists). Because
these classes are loaded from a separate class loader, which is not visible
to the Webapp class loader, they are not visible
to web applications.$CATALINA_HOME/classes
directory
(if it exists), and all JAR files in the $CATALINA_HOME/lib
directory (if it exists). All of the classes in these repositories will
be visible to all web applications, so they may be used to share
information between web apps.
(NOTE - this behavior is specific to Tomcat 4.0, and
will not necessarily be portable to other containers.)WEB-INF/classes
directory (if it exists), plus all JAR files
in the WEB-INF/lib
directory, for this web app. Because of
the parentage hierarchy, web applications can indirectly see (and therefore
load classes from) the Shared, Common,
System, and Bootstrap class loaders,
but not from the Catalina or
JasperX class loaders.$CATALINA_HOME/jasper
directory, which normally
includes the Jasper compiler classes and the XML parser that they require.
Because the parent of this class loader is the WebappX
class loader for this application, the JSP compiler can see all of the
JavaBean and other classes that are part of this application, but the
application classes cannot see anything loaded from here (and, in
particular, will not have access to the XML parser loaded by this
class loader.As you can see from the above descriptions, the contents of any
CLASSPATH
environment variable already existing in your server
is totally ignored. If you want to make a JAR file available to all web
applications, you must place a copy of this file in the
$CATALINA_HOME/lib
directory so that it becomes part of the
Shared class loader's repositories.
When a servlet (or JSP page) within a web application references a class
for the first time (either by using the new
operator or by
calling the Class.forName()
method), the following processing
occurs to locate and load the requested class:
loadClass()
method of the WebappX class
loader is called to load the specified class.java.*
),
it is loaded directly by the System class loader.ClassNotFoundException
.delegate
property is set to
true
(which is not the default), we will ask our
parent class loader to load this class before looking locally. This is
the standard Java2 delegation model, but prevents a web application from
overriding a class from the Shared class loader with its
own copy from WEB-INF/classes
or a JAR file in
WEB-INF/lib
.WEB-INF/classes
directory (if it exists), and then the JAR
files in WEB-INF/lib
.ClassNotFoundException
is thrown, as required by the Javadocs for a class loader.A similar pattern is followed when you call Class.getResource()
or Class.getResourceAsStream()
to access resources that are
co-resident with your classes.
Certain web application components (such as the Jasper JSP page compiler servlet, require additional information related to class loading to operate successfully. To avoid creating dependencies between the Jasper and Catalina code bases, this information is exposed as a set of servlet context attributes that are initialized when the web application is started. The following context attributes are created:
Previously, the Jasper page compiler was loaded in the
Shared class loader, along with the XML parser that it
requires. This had the side effect of causing this XML parser to be visible
to all web applications, through the inheritance hierarchy. However, this
causes problems if the JAR files of the selected XML parser are sealed (as are
the JAR files in the JAXP 1.1 reference implementation, for example) -- any
attempt to load your own XML parser (such as Xerces) from
WEB-INF/lib
would cause "package sealing violation" errors to be
thrown.
Now that the XML parser required by Jasper is loaded from the JasperX class loader, rather than the Shared class loader, this problem no longer occurs. However, any web application that relied on an XML parser being made available by Catalina will fail, because this is no longer true by default. If your web application requires an XML parser, you have three choices:
WEB-INF/lib
directory of your web application.$CATALINA_HOME/lib
directory so that they are available to all web applications. Note that
this is likely to introduce "package sealing violation" problems again,
so this option is only practical if your applications do not require
JSP pages.For more information about class loaders in general, see the Java Language Specification, and the Javadocs for the following classes:
java.lang.ClassLoader
java.net.URLClassLoader
The implementation class for all Catalina internal class loaders is
StandardClassLoader
. Required and available optional packages
are described using the Extension
class. For more information,
see the source code and/or Javadocs for the following classes:
org.apache.catalina.loader.StandardClassLoader
org.apache.catalina.loader.Extension