This article would focus on how Spring provides support for integration with JMX. JMX stands for Java Management Extensions and it is an API from Sun which can be used to manage as well as monitor any kind of Java resource. This article doesn’t aim to provide an in-depth coverage in JMX, however it provides a basic overview about JMX along with a sample Application. It includes a detailed step-by-step approach for integrating the JMX Environment into the Spring’s Framework.
also read:
2) Java Management Extension (JMX)
JMX is a management technology that can be used to manage any kind of resource. There have been various management technologies in the market for Network and Telephonic Domains. Though JMX is not specifically oriented towards any domain, it can be used to manage and monitor resources in any domain. The major levels defined in JMX are,
- Instrumental Level
- Agent Level
- Remote Management Level
2.1) Instrumental Level
For a resource to get monitored in JMX, it has to be instrumented as MBean and this is defined in the Instrumental Level. MBean stands for Manageable Bean and it has certain guidelines to be followed to conform to JMX standard. The guidelines will be applicable for the design of interfaces, attributes and exposed operations for MBeans.
2.2) Agent Level
This Level has two major components, one is the MBean Server and the other is the core set of services for the MBeans. MBeans tend to live in MBean Server so that they can be remotely monitored. The core set of services like Log Service, Timer Service, Accessibility Service will be applicable to the MBeans.
2.3) Remote Management Level
The core component in this level includes Connectors which are used by the Management Application to connect to MBean Server to get information about MBeans. The Reference Implementation (RI) from Sun includes a standard connector called RMI Connector which uses RMI protocol to connect to the MBean Server.
3) Example on JMX
In this section, let us develop a simple MBean and try to monitor it locally through an utility called jConsole
. The following steps have to be followed,
3.1) Creation of MBean interface
Let us try to instrument a Java resource called Service which exposes various operations like start()
, stop()
and execute()
. The naming convention is that all the MBeans interfaces must end with the suffix MBean. Let us look into the type definition,
ServiceMBean.java
package javabeat.net.articles.spring_jmx; public interface ServiceMBean { public void start(); public void execute(); public void stop(); }
3.2) Implementation for MBean interface
The following class will provide implementation for the above MBean. Since we are least bothered about the implementation, all the method definitions will just output a message describing the purpose of the method.
Service.java
package javabeat.net.articles.spring_jmx; public class Service implements ServiceMBean { @Override public void execute() { System.out.println("Service is running."); } @Override public void start() { System.out.println("Service has started."); } @Override public void stop() { System.out.println("Service has stopped."); } }
3.3) Registering the MBean
Once MBean is given implementation, it is ready to get registered with the MBean Server. An instance of MBean Server object can be obtained by calling ManagementFactory.getPlatformMBeanServer()
. After that the MBeans can be registered by calling the register()
method. Note that all the MBeans are given unique object names within the MBean Server and there are certain guidelines to be followed for naming a MBean.
RegisterServiceMBean.java
package javabeat.net.articles.spring_jmx; import java.lang.management.ManagementFactory; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; public class RegisterServiceMBean { private ServiceMBean mBean; public RegisterServiceMBean(ServiceMBean mBean) { this.mBean = mBean; } public void register() { ObjectName objectName = null; try { objectName = new ObjectName( "javabeat.net.articles.spring_jmx:type=ServiceMBean"); } catch(MalformedObjectNameException exception) { exception.printStackTrace(); } MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); try { mBeanServer.registerMBean(mBean, objectName); } catch(InstanceAlreadyExistsException exception) { exception.printStackTrace(); } catch (NotCompliantMBeanException exception) { exception.printStackTrace(); } catch (MBeanRegistrationException exception) { exception.printStackTrace(); } try { Thread.sleep(60 * 60 * 60); } catch (InterruptedException exception) { exception.printStackTrace(); } } public static void main(String[] args) { ServiceMBean serviceMBean = new Service(); RegisterServiceMBean object = new RegisterServiceMBean(serviceMBean); object.register(); } }
3.4) Monitoring the MBean
To monitor the behaviour of the MBean, follow the steps,
- Run the above program.
- Go the command prompt, set the path to
JDK\bin
and typejConsole
. - A window will open telling the currently running processes in the local system to which we want to connect to.
- Navigate to
javabeat.net.articles.spring_jmx.RegisterServicMBean
and click the connect button. - Go the MBean tab, expand the
javabeat.net.articles.spring_jmx
in the left side of the view to see the Service MBean.
4) Integrating Spring with JMX
The rest of the article deals with explaining the steps needed for Integrating Spring with JMX along with description in the relevant section.
4.1) Creating the MBean Implementation
Spring doesn’t mandate the developers to instrument the Java Resource in the traditional Interface-Implementation style. Developers are free to ignore the Interface for the MBean and directly go the implementation which is given below. The default strategy in this case is that all the public variables and the public methods are eligible to be monitored. Given below is the code listing for a MBean implantation called IntegrationMBean
which defines two attributes and one operation.
IntegrationMBean.java
package javabeat.net.articles.spring_jmx.integration; public class IntegrationMBean { private String strTestAttribute; private int intTestAttribute; public String getStrTestAttribute() { return strTestAttribute; } public void setStrTestAttribute(String strTestAttribute) { this.strTestAttribute = strTestAttribute; } public int getIntTestAttribute() { return intTestAttribute; } public void setIntTestAttribute(int intTestAttribute) { this.intTestAttribute = intTestAttribute; } public String performConcatenation(String str1, String str2) { return str1 + str2; } }
4.2) Configuring the Environment for Spring and JMX
spring-jmx-integration.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="integrationMBean" class="javabeat.net.articles.spring_jmx.integration.IntegrationMBean"> <property name="strTestAttribute" value="String Attribute Value"/> <property name="intTestAttribute" value="37"/> </bean> <bean id="mBeanExporter" class="org.springframework.jmx.export.MBeanExporter"> <property name="beans"> <map> <entry key="javabeat.net.articles.spring_jmx.integration:type=IntegrationMBean" value-ref="integrationMBean"/> </map> </property> <property name="notificationListenerMappings"> <map> <entry key="javabeat.net.articles.spring_jmx.integration:type=IntegrationMBean"> <bean class="javabeat.net.articles.spring_jmx.integration.IntegrationNotificationListener"/> </entry> </map> </property> <property name="server" ref="mBeanServer"/> </bean> <bean id="mBeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/> <bean id="serverConnector" class="org.springframework.jmx.support.ConnectorServerFactoryBean"> </bean> </beans>
This is the most important section as it contains almost all the configuration information for integration. Let us look into the bean information defined in the above Xml file one by one.
The bean definition starts with IntegrationMBean which defines the two properties along with property values. Next comes the declaration of the MBeanExporter
which when given with a set of Beans will export them to the MBean Server. Let us beak the bean definition further. It contains references to a list of MBeans which are identified by Object Names through the property name called 'beans'
. Following that is a property called 'notificationListenerMappings'
which takes a list of class names as argument through the tag called 'bean'
and they are used as listeners whenever a property of the MBean is updated. The third property contains a reference to the MBean Server to which the MBeans are to be exported.
The final section defines a server-connector with a well-defined service url to which other Management Applications or virtually any Application can connect to monitor the MBeans. Note that we haven’t supplied any service url for ConnectorServerFactoryBean
in which case the default url is 'service:jmx:jmxmp://localhost:9875'
.
4.3) Registering and Starting the Service
The process of registering the MBeans to the MBean Server and then starting a service url that can be accessible by the clients are all defined in the Xml file. We need to just make sure these operations are initiated to run the following program,
IntegrationMBeanTest.java
package javabeat.net.articles.spring_jmx.integration; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; public class IntegrationMBeanTest { public static void main(String[] args) throws Exception { try { Resource resource = new FileSystemResource( "./src/resources/spring-jmx-integration.xml"); BeanFactory beanFactory = new XmlBeanFactory(resource); System.out.println("Waiting for clients..."); } catch (Exception exception) { exception.printStackTrace(); } } }
4.4) Coding the Notification Listeners
While configuring the Xml file, we saw a property called 'notificationListenerMappings'
which acts as listeners for any property change in MBeans. The constraint is that the class must implement the interface NotificationListener
thereby overriding the method handleNotification()
.
IntegrationNotificationListener.java
package javabeat.net.articles.spring_jmx.integration; import javax.management.Notification; import javax.management.NotificationListener; public class IntegrationNotificationListener implements NotificationListener { @Override public void handleNotification(Notification notification, Object handback) { System.out.println(notification.getMessage()); System.out.println(notification.getType()); } }
4.5) Running the Client Application
The Client Application tries to connect the service URL through JMX Specific Api’s. After getting a connection, it tries to get an instance of the ObjectName by using the object name string of the IntegrationMBean. After that the method performConcatenation() with two arguments is invoked reflectively. Finally to verify whether the listeners are being notified, two of the properties defined in the Integration MBean are modified to force the notification event to happen.
IntegrationClient.java
package javabeat.net.articles.spring_jmx.integration; import javax.management.Attribute; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class IntegrationClient { public static void main(String[] args){ try { String serviceUrl = "service:jmx:jmxmp://localhost:9875"; JMXServiceURL serviceURL = new JMXServiceURL(serviceUrl); JMXConnector clientConnector = JMXConnectorFactory.connect( serviceURL, null); MBeanServerConnection mBeanClientConnection = clientConnector.getMBeanServerConnection(); System.out.println("Connected..."); String objectName = "javabeat.net.articles.spring_jmx.integration:type=IntegrationMBean"; ObjectName integrationMBeanObjectName = ObjectName.getInstance(objectName); String serviceName = "performConcatenation"; Object result = mBeanClientConnection.invoke( integrationMBeanObjectName, serviceName, new String[]{"one", "two"}, new String[]{"java.lang.String", "java.lang.String"}); System.out.println(result); mBeanClientConnection.addNotificationListener( integrationMBeanObjectName, new IntegrationNotificationListener(), null, null); mBeanClientConnection.setAttribute( integrationMBeanObjectName, new Attribute("StrTestAttribute", "New String Value")); mBeanClientConnection.setAttribute( integrationMBeanObjectName, new Attribute("IntTestAttribute", new Integer(3737))); } catch(Exception exception) { exception.printStackTrace(); } } }
also read:
5) Conclusion
Since JMX is a relatively new technology, the first half of the article spends time in explaining the basic concepts in JMX along with a sample Application. Then in the rest of the article, we have seen a step-by-step sample for Spring and JMX Integration that illustrates the support for JMX in Spring using which both these technologies can be coupled together and used effectively for Applications.