tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Johnny Kewl" <j...@kewlstuff.co.za>
Subject Re: Per Thread Class Loader... what do you think?
Date Mon, 06 Aug 2007 17:42:52 GMT

----- Original Message ----- 
From: "Leon Rosenberg" <rosenberg.leon@googlemail.com>
To: "Tomcat Users List" <users@tomcat.apache.org>
Sent: Sunday, August 05, 2007 12:38 PM
Subject: Re: Per Thread Class Loader... what do you think?


> could you elaborate a bit more why do you need the classloader to be per
> thread?
> In case that you really really need your own classloader for _some_
> objects, why don't you create a global classloader and load only those
> classes from it? why replace thread-classloader back and forth?

I wish I could..... I dont know how to create a global classloader that
takes control away from TC's WebApp classloader.

I'll try explain a little more....
This thing is an application server, I'm working on Rev3 of the thing and
its working wonderfully.... but it certainly is one complex animal.
When a remote Java Client (not browser driven) calls a class in the
repository on the webapp, I do what you thinking (I think;).... that is
I start a Special ClassLoader.... it knows how to get the class from the
repository "private classpath", it creates an instance, and returns a proxy
instance to the client.

The Java Client then calls a function 'say' runTest("MyTest")..... the
parameters are serialized, the proxy interface also transmitted..... on http
(binary) 'post'ed protocol..... it arrives at the servlet.... the param is
deserialized, the proxy interface deciphered... the instance looked up and
invoked.... the return parameters serialized.... its returned over the
wire... and the client feels like the java code is running right there on
their machine... in another country.

The parameters need not be primitive types.... on the client one can call
runTest(ObjectOnServer)-----(serialized etc)-----Injected and run on
server--- serialized back to client..... and it feels like its all running
at the client... etc etc.

The Special ClassLoader that is allowing access to the repository of
libraries on the server..... is designed to be replaced.
So for example, say you dump more classes onto the server (webapp).... you
can open the admin console and say, "gimme a new Special ClassLoader", that
will cause the system to load up the new classes for FRESH client requests,
in the new class loader (using the fresh classes), and when the old clients
are finished with their classes, the old classloader will free up and
destroy itself.  So its kinda cool because libraries can be changed,
updated, added to the live server.... no restart of the server needed, and
one never has old classes hanging around for all eternity.
 This also allows for clients to load up special singleton objects, which
are actually normal classes, but they get their own class loader. This is
where things like database pools hang out.... and other classloaders are
free to come and go as demand dictates. Anyway hope that explains why I dont
want classloaders to hang onto something..... and thats where the issue
comes in.

When a client does this.... runTest(ObjectOnLocalClientMachine)..........(it
gets serialized to the server).........Server picks up the interface....
says ah, this object does not exist on the server yet.... loads it with a
Special ClassLoader.... "inits" it with the serialized parameters.... passes
it into the class calling it.... it runs and returns to the client.... all
is wonderfull.... EXCEPT..... that thread is controlled by TC's WebApp class
loader.... and when "TC" instances the class loaded from the Special Class
loader.... for some reason.... that class in the special class loader....
will never ever release.
I think its because TC's class loader is used to resolve something during
the init.... maybe fetches OBJECT, or the serializer interface or
something.... so TC's class loader is hanging onto something that it loaded,
and my Special class loader is hanging onto the class.... and it wont let
go.... I have a feeling TC's CL also wont let go.... I can NULL all
instances.... force garbage collection... no way.
So that screws my design up, because that "hung" class loader will never
free.... and if its got 1000 old unused classes in it.... they will stay
there indefinitely.
As soon as I allow my Special Class Loader to control the thread.... ie do
ALL the class loading... and anything else that happens during serialization
and init'ing..... it will free up when the references to that serialized
object are killed or nulled.

..... its working very well.... much faster than soap will ever be.... but
the solution to this class loader funny, certainly feels odd (see below).
I agree... but the problem comes down to taking control away from TC's class
loader.... if I could I would let TC's_CL do it.... but it doesnt know how
to get the class.... its not in TC's classpath.... and if 2 class loaders
work together.... one getting the class.... and the other instancing
(resolving).... they dont release.
So... I have to steal control.... and the only way I know is to hijaak the
thread.
If I say run that code in the INIT of the servlet.... I cant defeat
TC's_CL.... its a different thread to the request thread.
If there is a way to override the TC class loader (in code).... that will
work across all threads.... please yell... I dont know how to do that....
but I have  feeling it cant be done... imagine.... TC's class loader is
special in that classes in the web app come first, imagine replacing that
with a conventional CL.... chaos.
As it stands.... my class loader has control, only while its in my code....

The problem only shows itself when parameter objects (having a serializable
interface) are serialized from client to server.... there is some subtle
thing happening with classloaders when this happens.... anyway I want to try
get rid of the fix below, even though it does work... busy making more
instrumentation to try watch the internals of all the class loaders.
At present have literally got the identical code down to.... let 2
classloaders do the job... problem... add the code below... ie one
classloader loading all classes.... beautiful.... because there is no
exception or bug as such.... when I trace through all the introspection
code, its not obvious which piece of code is causing the (wot I think) is a
cross class loader dependency.... the one wont free coz the other one has
something it depends on, and visa versa.

Interesting huh.... I'm trying to perfect an application server that can
take any code.... ie write the code, and then decide if you need an
application server... if so, just drop the jars into it.... thats the
idea.... ie trying to get around the problem of having to lock into an
application server... "just because you may need it".
Anyway hope that explains it..... its the sort of thing that would go
undetected, and would probably be of no importance in a normal app, or
servlet.

If you imagine a thread originating down there in TC's sockets

-----(coming into servlet)---(loading stuff in TC's CL)----(SPECIAL CL
supplies class)----(cl.Instance TC CL)---- PROBLEM
FIX
-----(coming into servlet REPLACE TC CL)---(loading stuff in SPEC
CL)----(SPECIAL CL supplies class)----(cl.Instance SPECIAL CL)---- WORKS

Code is identical except for the CL swap below.....been playing with it
whole weekend... no eurika yet.... so, any guess is good ;)

=================WORKS LIKE THIS ====================
>>     public void doPost(HttpServletRequest request, HttpServletResponse
>> response)
>>     throws ServletException, IOException {
>>
>>        //=======new DoServiceClass().doService(request, response)========
>>
>>         ClassLoader origClassLoader =
>> Thread.currentThread().getContextClassLoader();
>>         ExClassLoader localClassLoader = new
>> ExClassLoader(origClassLoader);
>>         String repository = dock.getRepository();
>>         localClassLoader.setRepository(repository);
>>         Thread.currentThread().setContextClassLoader(localClassLoader);
>>
>>         doServiceMain(request, response);
>>
>>         Thread.currentThread().setContextClassLoader(origClassLoader);
>>       //======================================================


=================FAILS LIKE THIS ====================

>>     public void doPost(HttpServletRequest request, HttpServletResponse
>> response)
>>     throws ServletException, IOException {
>>
>>        //=======new DoServiceClass().doService(request, response)========
>>
>>
>>         doServiceMain(request, response);
>>
>>       //======================================================
>>
>>     }
>> ________________________________________________________________
>>
>> Johnny Kewl
>>   eMail: John<No Spam>kewlstuff.co.za  -- replace <No Spam> with @ --
>>   Cell: +027-72- 473-9331
>> Java Developer (Tomcat Aficionado)
>>   Free Tomcat software at  http://coolese.100free.com/
>> ________________________________________________________________


---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message