More JMX in the Spring sandbox - No Fluff Just Stuff

More JMX in the Spring sandbox

Posted by: Craig Walls on August 13, 2004

Since my last post on Spring's JMX support, Rob Harrop has added even more cool stuff to the sandbox. In particular, he reacted to an exchange on The ServerSide between Ryan, Rob and myself by making it possible to use source-level metadata to decide whether or not a bean will be JMX-ified by Spring.

As you recall from my previous post (scroll down if you have forgotten), JmxMBeanAdapter adapts Spring-managed JavaBeans into JMX MBeans. To make it work, you had to give JmxMBeanAdapter a map of beans through it's "beans" property. As a reminder of how this might look:

  <bean id="jmxAdapter"
      class="org.springframework.jmx.JmxMBeanAdapter"
      depends-on="jmxServer"
      >
    <property name="beans">
      <map>
        <entry key="foobar:Name=myBean">
          <ref bean="managedBean"/>
        </entry>
      </map>
    </property>
  </bean>

That's fine, I suppose, but wouldn't it be even cooler if you could place an attribute in source-level metadata that indicates whether or not a bean should be exposed as a MBean?

The way JmxMBeanAdapter chooses which beans to expose as MBeans is through an assembler. By default it uses ReflectiveModelMBeanInfoAssembler which means that JmxMBeanAdapter uses the beans given to it in its beans Map. But MetadataModelMBeanInfoAssembler is an implementation of AutodetectCapableModelMBeanInfoAssembler (easy for me to say). An AutodetectCapableModelMBeanInfoAssembler is treated special by JmxMBeanAdapter. Instead of referring to its own Map of beans, JmxMBeanAdapter will let an AutodetectCapableModelMBeanInfoAssembler choose beans to be JMX-ified.

So, to make this all work, I've substituted JmxMBeanAdapter's default assembler with a MetadataModelMBeanInfoAssembler:

<bean id="jmxAdapter"
    class="org.springframework.jmx.JmxMBeanAdapter"
    depends-on="jmxServer"
    >
  <property name="assembler">
    <ref bean="metadataAssembler"/>
  <property name="namingStrategy">
    <ref bean="metadataNaming"/>
  </property>
</bean>

<bean id="metadataAssembler"
    class="org.springframework.jmx.assemblers.metadata.MetadataModelMBeanInfoAssembler">
  <property name="attributes">
    <ref bean="attributesImpl"/>
  </property>
</bean>

<bean id="metadataNaming"
    class="org.springframework.jmx.naming.MetadataNamingStrategy">
  <property name="attributes">
    <ref bean="attributesImpl"/>
  </property>
</bean>

<bean id="attributesImpl"
    class="org.springframework.metadata.commons.CommonsAttributes"/>

The first thing you'll notice is that there are a few more beans declared here than before. In addition to a MetadataModelMBeanInfoAssembler bean, I've also declared a MetadataNamingStrategy bean. This bean is then wired into the JmxMBeanAdapter's "namingStrategy" property to indicate that JmxMBeanAdapter should use consult the metadata to determine the MBean's ObjectName.

Here, I've given the "metadataAssembler" bean a reference to a CommonsAttributes bean. That indicates that I'm going to use Jakarta Commons Attributes to place the metadata in my bean's source code. I chose Commons Attributes because JSR-175 style metadata isn't available in Spring quite yet.

Commons Attributes is similar to JSR-175, but you place the attributes in JavaDoc comment blocks in a style that is similar to that of XDoclet (in fact, both XDoclet and Commons Attributes use XJavaDoc to parse metadata). If you want to know more about how to use Commons Attributes and how to incorporate it into your application's build cycle, visit the link in the last paragraph.

That brings us to the next step...instead of listing what beans I want to JMX-ify, I just tag them. For example:

/**
 * @@org.springframework.jmx.metatadata.support.ManagedResource(
 *     objectName="foobar:Name=myBean")
 */
public class FooBean {
  ...
  private String someProperty;

  /**
   * @@org.springframework.jmx.metatadata.support.ManagedAttribute()
   */
  public String getSomeProperty() { return someProperty; }
  public void setSomeProperty(String s) { someProperty = s; }

  /**
   * @@org.springframework.jmx.metatadata.support.ManagedOperation()
   */
  public void doSomething() {...}
  ...
}

The ManagedResource attribute accomplishes two things. In addition to telling MetadataModelMBeanInfoAssembler that this bean should be exposed as an MBean, it also specifies the ObjectName through its objectName property.

You'll also notice that I've tagged the getSomeProperty() method with the ManagedAttribute attribute. This indicates to MetadataModelMBeanInfoAssembler that I want the someProperty property to be exposed as a managed attribute. (Note that the ManagedAttribute attribute can be placed on either the setter or the getter.) Likewise, I've also tagged the doSomething() method with the ManagedOperation() attribute to tell MetadataModelMBeanInfoAssembler that I want to expose doSomething() as a managed operation.

BTW, in case you think it's a typing stutter, the double "@" used when declaring attributes is correct. That's how Commons Attributes knows that it's dealing with one of its attributes and not a JavaDoc or other doclet tag. Also, I've specified each attribute using its fully-qualified class name. This makes things more verbose, but I do this to make things clearer for the purposes of this article. There are ways to tell Commons Attributes to resolve attributes without specifying FQCNs...but I refer you to their documentation for that information (hint: notice the attributepackages parameter to attribute-compiler Ant task).

Credit where credit is due: Rob Harrop has done a fantastic job implementing JMX support in Spring. I look forward to this stuff being moved out of the sandbox and into an official Spring build someday.

This blog entry, the code examples, and any typos or blatant mistakes are entirely my own doing.

Craig Walls

About Craig Walls

Craig Walls is a Principal Engineer, Java Champion, Alexa Champion, and the author of Spring AI in Action, Spring in Action, and Build Talking Apps. He's a zealous promoter of the Spring Framework, speaking frequently at local user groups and conferences and writing about Spring. When he's not slinging code, Craig is planning his next trip to Disney World or Disneyland and spending as much time as he can with his wife, two daughters, 1 bird and 2 dogs.

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »