Announcement Announcement Module
Collapse
No announcement yet.
JMX / Tomcat / ClassLoader problem? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JMX / Tomcat / ClassLoader problem?

    I've been trying to get the new 1.2 JMX stuff working in Tomcat 5.5.7. I've run into some problems when invoking mbeans that load resources from the classpath. If I load the resource with:
    Code:
    Resource resource = new ClassPathResource("foo.xml", this.getClass().getClassLoader());
    things work OK. However if I just use:
    Code:
    Resource resource = new ClassPathResource("foo.xml"));
    the resource cannot be found. However if I invoke the latter statement from within the webapp (ie: not thru JMX) it does work.

    I believe this happens because the Thread's context ClassLoader is used by default in the ClassPathResource class, but when you invoke the method through Tomcat's JMX, this Thread context ClassLoader is not the same as the ClassLoader that was used to load the webapp - hence the resource cannot be found.

    What I'm trying to do is actually a little more complex than the example I gave above, and its failing because some internal spring classes don't specify the class loader explicitly when loading resources. It seems that I can't (easily) override/change this behaviour either.

    Any ideas on how I can fix this problem?

    Thanks,
    Charles

  • #2
    I would probably have to consider this a bug in TomCat, unless I'm missing something, as it's not setting the context classloader. While your first form may always work, it's actually not really correct either, since you _do_ generally want to use the context classloader, not the classloader of the class doing the loading, which may not actually be the same thing.

    Comment


    • #3
      OK, but I wouldn't discount the possiblity that I'm doing something dumb as my JMX knowledge is not the greatest. Perhaps I could verify that my approach is correct.

      I set up tomcat 5.5.7 for JMX using (more or less) the instructions at http://mc4j.sourceforge.net/usageTomcat.html. I then added the following bean to my bean definition xml:
      Code:
          <bean id="jmxExporter"
              class="org.springframework.jmx.export.MBeanExporter">
              <property name="beans">
                  <map>
                      <entry key="bean&#58;name=myBean">
                          <ref local="myBean" />
                      </entry>
                  </map>
              </property>
          </bean>
      Then I connect a JMX client (mc4j or jconsole) to the tomcat mbean server and I can see "myBean" (as well as all the other tomcat mbeans) and invoke operations on it, but I get the resource problem above.

      Would you expect this to work? Do I have to define my own MBeanServerFactoryBean or ConnectorServerFactoryBean, instead of relying on the default Tomcat mbean server? I have tried doing this, but with no success (although I was shooting in the dark somewhat, as I can't find any up-to-date documentation on this stuff).

      Any help appreciated.

      Thanks,
      Charles

      Comment


      • #4
        Charles,

        I don't think you are doing anything wrong in your code - rather this is more a nuance of the Tomcat class loader and its interaction with JMX. A way around this might be to let Spring inject the Resource instance for you if that is possible.

        I think in this particular situation your code is correct, because you do want the classloader for the WAR to do the loading of resources not the JMX context class loader (which isn't being set correctly by Tomcat). I'd be inclined to write a simple algorithm that checked both the context class loader and the class loader of your MBean class - perhaps even factor out a strategy interface that hides the resource lookup behaviour.

        Rob

        Comment


        • #5
          OK, thanks Rob. I can get around the problem that lead to my initial post.

          However, even if I changed my resource loading strategy to what you suggest, it makes me nervous that other Spring code that I do not control will not use this strategy and hence may fail. For example, my original problem arose when trying to lazily load a spring bean factory, which makes heavy use of the context class loader.

          Do you think its worth asking on the Tomcat list to find out if there's any change that they can make that would make an mbean invocation run with the correct context classloader?

          Cheers,
          Charles

          Comment


          • #6
            Charles,

            I'll do some more testing with Tomcat when I have some time to see if I can find the exact cause of the problem and submit a patch to them - I'll also mention this to the Tomcat guys to see if they have any idea what is happening.

            Rob

            Comment


            • #7
              Thanks Rob! FYI, I think this problem also manifests when invoking an operation on a spring mbean that has been defined with lazy-init="true" but which has not yet been loaded.

              Cheers,
              Charles

              Comment

              Working...
              X