tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From delbd <de...@oma.be>
Subject Re: WebappClassLoader - don't understand what's happening
Date Thu, 02 Jun 2005 14:01:57 GMT
Le Jeudi 2 Juin 2005 14:50, Herrmann, Sascha (GE Healthcare) a écrit :
> > Any library having static methods like
> > SomeLibraryClass.setXYZ(xyz);
> > SomeLibraryClass.getXYZ(xyz);
>
> Wow, wow, wow .... . You mean any class that has static methods gets
> shared?? Any class that calls static methods? Could you explain that a bit
> further, please?
>

No, i mean a shared class which has static methods could potentially serves as 
a bridge for objects between web applications :)  
I forgot the 'shared' in the sentence 'Any shared library having static 
methods', sorry ;)

> > so i doubt usefull informations comes from it.
>
> It works for all the other methods I put this code in. It seems that Tomcat
> assigns the CL to thread when it's fetched from the pool.

Possible, might have a sense in terms of security.

>
> It's definitely the case. We have a static log variable in the classes. It
> holds the log4j logger reference. All the debug output from the class goes
> into the log file of the application that started first (the one that
> loaded the class). Even the output when I use the app that was started
> second. That's how I noticed in the first place.
>

is log4j a shared lib? if this is the case, might explain why all logs are in 
one common file (see log4j explanations for details, it's stated log4j should 
be put in WEB-INF/lib and nowhere else to prevent problems in J2EE 
environnement). In your case, this simply mean the config is shared, like is 
the log4j libraries. 
Don't mis this point: static Logger Logger.getLogger(SomeClass.class), does 
not mean the logger is 'the one for the class' but this mean the Logger is 
'the one having the name some.package.SomeClass' this difference is subtle 
but has lots of implications when several different classes with excaclty the 
same name and package are using a common Log4j library.

> Are you familiar with the classloading stuff?
>

did lose my mind in the maze of classloading several time.

> I was wondering ... when the WebappClassLoader doesn't find the class in
> its path, and then delegates the loading to the shared classloader ... and
> when then the shared classloader loads the class .... who resolves the
> dependecies of this loaded class? Does the WebappClassLoader get a shot
> first, or is it still the shared classloader?

when the shared class loader loads a class in the delegation model, it assigns 
itself to the class.getClassLoader(). That is any other class further loaded 
by object of the first class will be loaded using the shared classloader. 
This is the excpected behaviour. So in your question, the answer is "no the 
WebappClassLoader is not given a chance to resolve as shared classloader does 
not know it's childrens"

>
> What if the shared classloader loads a class, and then cannot resolve a
> referenced class (because it's in one of the app's WEB-INF\lib directories)

the sharedclassloader is unable to load anything in WEB-INF/lib, because it 
doesn't know about it.
So in your case, it will ask it's parent (probably the JVM classLoader) which 
will throw a ClassNotFoundException


> ... how does he determine which child WebappClassLoader he is to use? And
> who is registered in the JVM then as initiating classloader?

The delegation model goes down - top (from the calling class' classloader to 
the root classloader), it nevers goes back down later. A class instanciated 
by the shared classloader, is *never* able to load any class from a 
WEB-INF/lib using Class.forName()

>
> I am asking because we have classes in our shared\lib directory. Those
> classes use a factory pattern to instantiate classes (that can be in the
> WEB-INF\lib dirs). Now, I wonder how these classes are loaded, that the
> factory class in shared\lib needs?

Sorry but if factories are in shared/lib, they are unable to load anything 
from WEB-INF/lib .... with one exception, if they are passed as argument the 
classloader of the WEB-INF/lib to use, they can use it to instanciate the 
class. But this is not a suggested way to write factories.
However, a better behaviour would anyway be to put those factories in 
WEB-INF/lib insteed of shared/lib

>
> Or am I thinking in the wrong direction? Does the WebappClassLoader always
> try first?
>
> Damn, I wish I would know this classloading stuff better.

We all learned the way they work the hardway ;)
and yes you are thinking in the wrong direction, you think the delegation 
model is a 2 way path. This is not, it's a no return path.

>
> Do you have an idea why I cannot get logging output from the
> WebappClassLoaderS?

see messages above. ;)

>
> Sascha
>
> > -----Original Message-----
> > From: delbd [mailto:delbd@oma.be]
> > Sent: Thursday, June 02, 2005 2:32 PM
> > To: Tomcat Users List
> > Subject: Re: WebappClassLoader - don't understand what's happening
> >
> > Le Jeudi 2 Juin 2005 13:49, Herrmann, Sascha (GE Healthcare) a écrit :
> > > Thanks for your reply.
> > >
> > > It could be. How is a class "pushed" to a shared library?
> >
> > Any library having static methods like
> > SomeLibraryClass.setXYZ(xyz);
> > SomeLibraryClass.getXYZ(xyz);
> >
> > > I used the following code:
> > >
> > >       System.out.println( "BoneDBTransactionImpl2  LOADING
> > > ***************************************" ); System.out.println(
> > > "Thread Classloader is: " +
> > > Thread.currentThread().getContextClassLoader() );
> >
> > System.out.println(
> >
> > > "Hash: " +
> > > Thread.currentThread().getContextClassLoader().hashCode() );
> > > System.out.println( "Class: " +
> >
> > Thread.currentThread().getContextClassLoader().getClass().getName() );
> >
> > > System.out.println( "---------------------------     " );
> > >       System.out.println( "Class Classloader is: " +
> > > BoneDBTransactionImpl2.class.getClassLoader() );
> >
> > System.out.println( "Hash:
> > > " + BoneDBTransactionImpl2.class.getClassLoader().hashCode() );
> > > System.out.println( "Class: " +
> >
> > BoneDBTransactionImpl2.class.getClassLoader().getClass().getName() );
> >
> > > System.out.println( "BoneDBTransactionImpl2  LOADING
> > > ***************************************" );
> >
> > Tss tss tss, the Threads instances are started by
> > catalina-http and shared inside a Thread pool amongst tomcat
> > application if am not wrond, so i doubt usefull informations
> > comes from it.
> > Only usefull information should comes from
> > BoneDBTransactionImpl2.class.getClassLoader() as this is the
> > classloader which will load any class needed by
> > BoneDBTransactionImpl2.
> >
> > > I put this into a static initializer block of a class that
> >
> > is in a jar
> >
> > > in both WEB_INF\lib directories. I also added this code the
> > > constructor of that class. And to make sure to see what
> >
> > loader belongs
> >
> > > to what app I also added the code to some methods of
> >
> > classes that are
> >
> > > either in app A or in app B and not in both.
> > >
> > > I start app A. The output shows that
> > >
> > > - the class is loaded in app A by WebappClassLoader with hash A
> > > - the instance is created in app A using the Class loaded by
> > > WebappClassLoader with hash A. - Thread context classloader is
> > > WebappClassLoader with hash A.
> > >
> > > Then I start app B. The output shows that
> > >
> > > - the instance is created in app B using the Class loaded by
> > > WebappClassLoader with hash A - Thread context classloader is
> > > WebappClassLoader with hash B.
> >
> > Strange indeed, so you mean when starting app B, the static block of
> > BoneDBTransactionImpl2 is never executed? If that's the case
> > this indeed mean the class was already loaded before. Either
> > this mean you have another lib in webapp B requiring
> > BoneDBTransactionImpl2 and you didn't see the static init
> > message 50 lines before ;), either you indeed have something shared.
> >
> > One easy way to check
> > In webapp A, create a servelt which will set to 1 a static boolean in
> > BoneDBTransactionImpl2 and in webapp B, set another servlet
> > which will read the value of this boolean.
> > first access B servlet to ensure boolean is set to false
> > acces A servlet to switch boolean to true re-access B servlet
> > to check if boolean has switched value in B webapp
> >
> > If that's the case, this really mean class is shared by
> > webapp class loaders, serious problems ahead for tomcat team ;)
> >
> > > The class exists in jar files in both WEB-INF\lib
> >
> > directories, but not in
> >
> > > any other lib directory. And - if the class was loaded by a shared
> > > classloader, shouldn't the xxx.class.getClassLoader() return the
> > > StandardClassLoader?
> >
> > dunno
> >
> > > I must admit that I am not too familiar with the deeper
> >
> > concept of J2EE
> >
> > > classloading apart from the information found on some web pages.
> >
> > me too ;) however, separation in webapps mean every ressource
> > in a .war is not
> > to be shared with any other webapp.
> >
> > > So, if the class indeed is loaded by WebappClassLoader A,
> >
> > how can it be
> >
> > > "pushed" to become a shared one? And how can I prevent this
> >
> > from happening?
> >
> > > Or am I making a mistake reading the output? I am sure that
> >
> > the class is
> >
> > > not loaded again.
> >
> > see message above, i just didn't know how you concluded the
> > class was shared,
> > one common error is to give an instance of some object to a
> > shared library
> > and retreive it in another webapp, not understanding this
> > object you are
> > manipulating is a stranger ;) not your case scenario you describe.
> >
> > > I checked the sources in Apache's CVS. I noticed that there
> >
> > is quite some
> >
> > > debugging put into WebappClassLoader. But I can't get my
> >
> > server to log
> >
> > > these messages. I have the log4j and commons logging jars
> >
> > in my common\lib
> >
> > > directory and my log4j.properties (root logger set to debug) in my
> > > common\classes directory. I also set the debug to "4"
> >
> > everywhere in my
> >
> > > server.xml. I see some catalina debug messages, but I cannot see the
> > > messages from the WebappClassLoader. So what am I doing
> >
> > wrong? I believe
> >
> > > the debug output would be very helpful in understanding the problem.
> >
> > Yes have same problem here to get usefull log messages from
> > Realms. Seems you
> > have to modify directly the logging level in your java home,
> > logging.properties (and setting it to debug for whole jvm is
> > VERY verbose)
> >
> > > Sascha
> > >
> > > > -----Original Message-----
> > > > From: delbd [mailto:delbd@oma.be]
> > > > Sent: Thursday, June 02, 2005 12:33 PM
> > > > To: Tomcat Users List
> > > > Subject: Re: WebappClassLoader - don't understand what's happening
> > > >
> > > > This indeed should not happen as this would break sun specs.
> > > > I would be quite surprised it it was at all possible :/ How
> > > > did you conclude the webappclassloader is sharing the class
> > > > between webapps in your case?
> > > >
> > > > Are you sure you are not mistakenly using a shared class?
> > > >
> > > > Not only does every webapp has his very own
> > > > webappclassloader, but if you reload the webapp (using the
> > > > manager/html interface) this should also create a new
> > > > webclassloader and reload all classes (did you check it was
> > > > the case?).
> > > >
> > > > Am also using tomcat 5.5.7 here, with jdk 1.4.2_05-b04 and we
> > > > didn't notice such a problem. We can deploy several webapps,
> > > > all using a library in WEB-INF/lib which is crating
> > > > singletons. All webapp has it's own sets of singletons.
> > > >
> > > > Could it be that you are in fact doing such scenario?
> > > >
> > > > - create an object of class A in webapp1 using webappclassloader1
> > > > - push this object to some library shared between webapplications
> > > > - retrieve the object from shared library in webapp2 (as this
> > > > is via a shared library, it's possibile to do and you and up
> > > > manipulating in webapp2 an object who's classloader is
> > > > webappclassloader1)
> > > > - in webapp2, calls something like a.createB() to get an
> > > > object of class B and be surprised that the class of B was
> > > > created using webappclassloader1
> > > >
> > > > Le Jeudi 2 Juin 2005 10:59, Herrmann, Sascha (GE
> >
> > Healthcare) a écrit :
> > > > > We are facing a problem with Tomcats WebappClassLoader.
> > > > > We deploy several of our own applications on one Tomcat server.
> > > > >
> > > > > It seems that the WebappClassLoaderS are not isolated but share
> > > > > classes instead. Why would that be?
> > > > >
> > > > > Judging from the (well, outdated) classloader
> >
> > documentation, this
> >
> > > > > should never happen.
> > > > > If an application tries to use a class, and the class is in
> > > >
> > > > a jar in
> > > >
> > > > > its WEB_INF\lib directory, then the class should be
> >
> > loaded by the
> >
> > > > > application's very own WebappClassLoader. It should not be
> > > >
> > > > available
> > > >
> > > > > to other WebappClassLoaderS, isn't that correct? I quote:
> > > > >
> > > > > "All unpacked classes and resources in the /WEB-INF/classes
> > > >
> > > > directory
> > > >
> > > > > of your web application archive, plus classes and
> >
> > resources in JAR
> >
> > > > > files under the /WEB-INF/lib directory of your web application
> > > > > archive, are made visible to the containing web
> > > >
> > > > application, **but to no others**."
> > > >
> > > > > Instead of sharing the class, the second WebappClassLoader
> > > >
> > > > should load
> > > >
> > > > > the class again, shouldn't it?
> > > > > So why does a WebappClassLoader here re-use a class already
> > > >
> > > > loaded by
> > > >
> > > > > the WebappClassLoader of another application?
> > > > >
> > > > > We're running 5.5.7 on JDK 142_08.
> > > > >
> > > > > Thanks in advance!
> > > > >
> > > > >
> > > > > Sascha Herrmann
> > > > > Engineering (Java)
> > > > > GE Healthcare
> > > > > Technologies
> >
> > ---------------------------------------------------------------------
> >
> > > > > To unsubscribe, e-mail:
> >
> > tomcat-user-unsubscribe@jakarta.apache.org
> >
> > > > > For additional commands, e-mail:
> >
> > tomcat-user-help@jakarta.apache.org
> >
> > > > --
> > > > David Delbecq
> > > > Royal Meteorological Institute of Belgium
> > > >
> > > > -
> > > > Is there life after /sbin/halt -p?
> >
> > ---------------------------------------------------------------------
> >
> > > > To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail:
> >
> > tomcat-user-help@jakarta.apache.org
> >
> >
> > ---------------------------------------------------------------------
> >
> > > To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
> >
> > --
> > David Delbecq
> > Royal Meteorological Institute of Belgium
> >
> > -
> > Is there life after /sbin/halt -p?
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-user-help@jakarta.apache.org

-- 
David Delbecq
Royal Meteorological Institute of Belgium

-
Is there life after /sbin/halt -p?

---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-user-help@jakarta.apache.org


Mime
View raw message