Announcement Announcement Module
Collapse
No announcement yet.
Different ClassLoaders Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Different ClassLoaders

    (I posted a the same question on WowzaMedia forums, so I'll just copy the most of it)

    Hi,


    I'm having problems using @AspectJ Spring annotations inside a Java Flash Media server called Wowza.
    This is a rather weird problem, so I'll be long in the explanation to make sure you get me right.

    When I launch the application as a standalone java app, I can see this in the logs:

    Code:
    [AppClassLoader@130c19b] info AspectJ Weaver Version 1.6.2 built on Saturday Oct 4, 2008 at 05:47:07 GMT
    [AppClassLoader@130c19b] info register classloader sun.misc.Launcher$AppClassLoader@130c19b
    As you can see, the classloader in use by AspectJ's weaver is AppClassLoader. If I create something in my program with new operator, the ClassLoader is also AppClassLoader. Same classloader means that the objects are advised (as expected) and therefore I'm happy.

    Now here's where everything goes south:

    Code:
    [URLClassLoader@10385c1] info AspectJ Weaver Version 1.6.2 built on Saturday Oct 4, 2008 at 05:47:07 GMT
    [URLClassLoader@10385c1] info register classloader java.net.URLClassLoader@10385c1
    This is the same output as above, but running the application from within Wowza. By "running from within Wowza" I mean that I start the server by calling its bootstrap and my code is called due to a custom-made module that I configured there. Think servlets here; I configure a context, make a couple of classes and configure some files, the app-server launches, fires up my context and off my code goes happily executing.

    Now this classloader thing wouldn't be much of a big deal, if it wasn't for the fact that everything I create using new still comes from AppClassLoader and not from URLClassLoader.

    Since LTW can only be applied on classes from the same ClassLoader, you can see where this is headed - absolutely no @AspectJ AOP whatsoever.

    Playing around with the code, I found out I can still use AOP if I restrict myself to using Spring's AOP (applied only to Spring managed objects) but this doesn't fit my purposes as I have lots of background stuff that Spring doesn't control and I need to apply AOP to those objects as well. Interesting fact is that Spring's unadvised beans come from AppClassLoader, while Spring's advised beans come from URLClassLoader.

    Here's an example:
    Code:
    StuffInterface advisedBean = (StuffInterface) context.getBean("bean");
    System.out.println(advisedBean.getClass().getClassLoader());
    OtherStuff unadvisedBean = (OtherStuff) context.getBean("unadvisedBean");
    System.out.println(unadvisedBean.getClass().getClassLoader());
    And the results, standalone and within Wowza (in that order):

    Code:
    > Standalone mode
    sun.misc.Launcher$AppClassLoader@130c19b
    sun.misc.Launcher$AppClassLoader@130c19b
    Code:
    > Within Wowza
    java.net.URLClassLoader@10385c1
    sun.misc.Launcher$AppClassLoader@130c19b
    Now, I have no idea where is the root of this problem. I've searched Spring's source code and URLClassLoader is nowhere to be found. I doubt this is Wowza's problem either, but the weird thing is that it only happens inside Wowza - which I now know for a fact has its own classloader, but like I said before, objects created using new still come from AppClassLoader, only woven stuff comes from URLClassLoader.

    Any hints on this? I'm about to try a different approach: launching the application server from within my code instead of expecting my code to be launched by the app server. But that feels so ass-backwards... :\


    Best regards,
    Bruno

  • #2
    Talking to the folks at Wowza, I now know that the URLClassLoader is being created by them and it's set as the context classloader.
    So I've managed to fix it using two different approaches. One is creating the context first (while the context classloader is still untouched) and after call

    Code:
    Bootstrap.main(...);
    launching the server from within my code (a bootstrap wrapper). While it doesn't feel totally right, it does allow me to instrument the app server's code which would be nice if I needed it. Does break app server context isolation, since all classes loaded after the weaver has been loaded can potentially be woven.

    The other approach is when my module is loaded from within the app server (the normal flow), execute this:

    Code:
    Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
    right before the new ClassPathXmlApplicationContext(...). Remember that every object created using new operator had the AppClassLoader classloader, so this is basically just "fixing" context classloader to what it was before Wowza changed it. This is a more isolated change.

    While both solutions are working and no real ugly hacks were needed, I would still like to know why when I create new instances of objects, they are created by the AppClassLoader and every instrumented thing goes under the URLClassLoader.
    Last edited by ovokinder; Jul 18th, 2009, 09:33 PM.

    Comment

    Working...
    X