Monday, November 4, 2013

Spring JMX - Expose POJOs as MBeans

Spring JMX allows you to easily expose POJOs as JMX MBeans. Even it allows the MBeans to deploy on application server which has MBean server running or can be run standalone. We can use jconsole to run the services provided by the MBean.
The configuration required to expose the POJO as Mbean is as follows. Here, MyBean is a POJO with at-least one public method.
<bean id="myMBean" class="com.test.MyBean"  />

<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
   <property name="beans">
       <map>
          <entry key="bean:name=MyMBeanName" value-ref="myMBean" />
       </map>
   </property>
</bean>
MBeanExporter exposes the map of "beans" as MBeans. Here we exposed myMBean as "MyMMBeanName". This name will be shown in the jconsole. By default, all the public methods inside the POJO will be exposed as operations.
If the Spring JMX is not running under an application server, then we need a starter. Definition is as follows:
<!-- If not running on a server which has MBean server running, you must start here -->
<bean id="factory" class="org.springframework.jmx.support.MBeanServerFactoryBean" />
With the above configuration, The MBean can be accessed locally. The MBean can be exposed either using JMXJMP or RMI.
To expose using JMXJMP as follows. The default service URL to access is : service:jmx:jmxmp://localhost:9875
<bean class="org.springframework.jmx.support.ConnectorServerFactoryBean" />
To expose using RMI as follows.
<bean class="org.springframework.jmx.support.ConnectorServerFactoryBean"
    depends-on="rmiRegistry">
    <property name="objectName" value="connector:name=rmi" />
    <property name="serviceUrl"
        value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
</bean>

<bean id="rmiRegistry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
    <property name="port" value="10099" />
</bean>
The complete configuration of exposing POJO using Spring JMX (With Remote access with RMI) without running an application server is as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-3.0.xsd">

    <bean id="myMBean" class="com.test.MyBean"  />

    <bean class="org.springframework.jmx.export.MBeanExporter"
       lazy-init="false">
       <property name="beans">
           <map>
           <entry key="bean:name=MyMBeanName" value-ref="myMBean" />
           </map>
        </property>
    </bean>

    <!-- If not running on a server which has MBean server running, you must start here -->
    <bean id="factory" class="org.springframework.jmx.support.MBeanServerFactoryBean" />

    <bean class="org.springframework.jmx.support.ConnectorServerFactoryBean"
        depends-on="rmiRegistry">
        <property name="objectName" value="connector:name=rmi" />
            <property name="serviceUrl"
               value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
    </bean>

    <bean id="rmiRegistry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
        <property name="port" value="10099" />
    </bean>

</beans>
The POJO MyBean.java is :
package com.test;

public class MyBean {
    public void start()
    {
        System.out.println("Started");
    }
 
    public void stop()
    {
        System.out.println("Stopped");
    }
}
The Application program to start is :
package com.test.application;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {
   public static void main(String...args)
   {
       ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
       context.getBean("factory");
   }
}
When we run this program, it start the MBean. Connect to this using jconsole. The MBean with name "MyMBeanName" visible under MBeans Tab.

Happy Learning!!!!