Andrey Myatlyuk wrote:

> Hello Vladimir,
>
> Thank you for your help.
>
> And I'm still have some questions.
>
> Why do we need to implement "some interface"? java.io.Serializable I
> think? But anyway I implemented this interface - it doesn't work. This
> approach works for EJB. :)
>
> And my question is: Is there any way to use "some shared" object with
> reloadable servlets without Tomcat restart?
>
> Thanks.
>
> Wednesday, March 14, 2001, 3:16:45 PM, you wrote:
>
> VG> I think you're experiencing a standard Java class loader problem.
> VG> Java treats classes loaded into different classloaders as different
> VG> classes, even though they share the same full. qual. name.
> VG> Your recompiled servlets are reloaded by a brand new class loader
> VG> to make sure the old classes are garbage collected. What you get
> VG> from the context is actuially an instance of a class loaded into
> VG> a different classloader, and (StatesBean) part in your statement
> VG> causes StatesBean to be loaded again by this new classloader that
> VG> reloaded your servlet, so
> VG> VM complains that you cannot cast objects since it thinks they
> VG> are instances of 2 completely different classes. No matter where
> VG> you place your files you'll have the same problem.
>
> VG> You can avoid this problem by writing some extra code and have your
> VG> bean to implement some interface.... Extra work, just restart
> VG> Tomcat every time...
>
> VG> Regards,
> VG> VG.
>
> VG> Andrey Myatlyuk wrote:
> >>
> >> Hello Tomcat users,
> >>
> >> I'm in a trouble. I share some object(StatesBean) between servlets. And when I
> >> recompile _servlet_, I got ClassCastException about shared object.
> >>
> >> _statesBean=
> >>     (StatesBean)getServletContext().getAttribute(StatesBean.STATES_BEAN_NAME);
> >>
> >>
> >> Classfile for this object is placed in the same directory, where
> >> servlets do - web-inf/classes. Where I need to place classfile for
> >> this object to prevent Tomcat exceptions?
> >>
> >> Of course, if I reload Tomcat everything is OK.
> >>
> >> Thank you in advance!
> >>
> >> --
> >> Best regards,
> >>  Andrey                            mailto:[EMAIL PROTECTED]
> [...]

Hi :-)  I am not sure, I guess:
 * perhaps the problem is:
    - let use suppose:   classloaderA -> classA -> instanceA
      then you "setAttribute"  instanceA into ServletContext of
      this wepapp, so now ServletContext holds a reference to
      instanceA.
    - after a while, your Sevlet class is reloaded, with
      jakarta-tomcat-4.0-b1, now classloaderA is not there,
      so classA is not there, But instanceA is there: because
      at least there is One reference of instanceA is being holded
      by ServletContext, so it will not be GCed, and getAttribute()
      will not return null.
   - but now instanceA doesn't has "its original class" and "its
     original classloader", I am not sure, but I guess perhaps it is
     the reason.

*  IMHO, I guess:  if you can find a way to load classA from a
    special classloader which will not be destroyed when/even if
    your Servlet class is reloaded, then you can solve the problem.
    It means that our Servlet class and some Helper classes are
    loaded by several classloaders in "diferent layer". if we don't
    want to keep a Attribute "across Servlet reloading", perhaps
    we don't need to it; but if we want, and we are sure that the
    "webapp classloader" will be destroyed and re-made, than I
    guess perhaps we have to use classloaders which are in
    "diferent layer".

*   the following is a good email about the classloader:

//************  <good email> ************************
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

//************  </good email> ************************



Bo    ^_^
Mar.14, 2001


Reply via email to