On Sat, 10 Mar 2001, David Wall wrote:
> There appears to be a serious problem with the classpath/classloader with
> Tomcat 3.2.1.
>
> It may be related to the Jasper engine, which outputs a dynamic classpath
> name that includes all of the classes and jars in the WEB-INF directory, as
> expected. But is the same classloader used when servlets are loaded at
> startup according to the web.xml file?
>
The same class loader is used to load all classes within a particular web
application, but there is more to the story than that. See below.
> Anyway, I'm not sure where the problem resides, but I have found that by
> setting the CLASSPATH to the same thing Jasper sets up (specifically those
> files in WEB-INF/classes and WEB-INF/lib), my beans will no longer complain
> about unknown classes.
>
> But unfortunately, this "fix" doesn't really work because apparently they
> really are loaded by different classloaders, so they are not the same
> classes within the JVM. This causes problems for classes that appear to
> have been initialized, but then magically are not when loaded through the
> other classloader.
>
The most common cause for this is actually a developer error. Before
explaining how this can be true, let's look a little at how class loading
actually works in Tomcat (the details do ***not*** necessarily apply to
any other servlet container, because standard behavior is not specified).
There is actually a hierarchy of class loaders created when Tomcat is
running:
- Bootstrap class loader (Java system classes)
- Extensions class loader (JAR files from $JAVA_HOME/jre/lib/ext)
- System class loader (contents of CLASSPATH at startup time)
- Webapp class loader (contents of WEB-INF/classes and WEB-INF/lib
for your particular web application)
Now, when your servlet class is loaded, Tomcat asks the webapp class
loader to load it. Following the standard Java delegation model, the web
app class loader first asks it's parent class loader to try to find the
class -- and so on up the hierarchy. If your servlet class is actually in
WEB-INF/classes or WEB-INF/lib, all of these attempts to delegate upwards
will fail. Therefore, the web app class loader will load the class
itself.
The same thing happens for every other class that your servlet references
-- it gets loaded by whichever class loader finds that class. If the load
happens from a class loader *above* the calling class's class loader, that
is fine. However, trouble occurs if you try the opposite direction,
because there are no links *downward* in the class loader hierarchy.
Consider what happens if you put your servlet class into $TOMCAT_HOME/lib
(so that it gets added to the system class loader at startup time). When
you reference the servlet, it gets loaded by the system class loader --
not the web app class loader. So, if it tries to refer to a JavaBean
class you have stored in WEB-INF/classes or WEB-INF/lib. What
happens? You've got it: ClassNotFoundException. Because the servlet was
loaded from the system class loader, it can only look *up* the hierarchy
rather than *down*.
> Anyway, is there anybody looking into this? I know I've seen several
> postings complaining about classpath problems that are likely related to
> this. Has it been fixed in 3.2.2?
>
The moral of the story is that you should follow the following steps to
completely avoid class loading problems in your web apps, and guarantee
that your apps will be portable to other servlet containers:
* Do not rely on system extensions in $JAVA_HOME/jre/lib/ext. If you
do, those classes are *not* allowed to reference any classes on the
system class path, or inside your web application.
* Do not rely on adding classes onto your CLASSPATH (or putting them in
$TOMCAT_HOME/lib) before starting Tomcat. Such classes will have
problems with downward references, as described above. Also, support
for shared library classes is ***not*** required by the servlet spec,
so you cannot count on this facility in a portable app.
* Put all classes your application needs into WEB-INF/classes, or
in JAR files unde WEB-INF/lib. In this way, they will all be loaded
by the same class loader and not have any referencing problems.
There are other specific issues with specific libraries, and there are
some changes in how class loading works in Tomcat 4.0, but the above
outline identifies what to do about the majority of class loading issues
in servlet containers.
> Thanks,
> David
>
Craig McClanahan
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]