Using Jmx in Java Web Application

In this article I would like to introduce a Jmx technology and a practical example that we can use in our applications.

I think Jmx is a good technology, based on MBean, but it’s not so known as it should be. The consequence is that it’s not so used.

JMX (Java Management Extensions) is a Java standard (JSR-000003) used for managing the resources of applications. I find it very useful for expose all that object properties during an application running. Alternative is to fill the code with log information and take a look at the log files.

Using Jmx allows us to monitoring all this data in better way. I want to show this data using JConsole already exists in Jdk (since 1.4 version … I’m not sure..).

Let’s start to define the order interface.


package it.samplespringjmx;

import java.util.Date;

public interface IOrderJmx {
 
 public String getOrderId();
 
 public void setOrderId(String orderId);
 
 public Date getOrderTime();
 
 public void setOrderTime(Date orderTime);
 
 public boolean isActive();
 
 public void setActive(boolean isActive);

}

And its base implementation:


package it.samplespringjmx;

import java.util.Date;

import javax.management.Notification;

import org.springframework.jmx.export.notification.NotificationPublisher;

import org.springframework.jmx.export.notification.NotificationPublisherAware;
public class OrderJmx implements IOrderJmx  {

 private String orderId;
 private Date orderTime;
 private boolean isActive;
 private NotificationPublisher publisher;
 private int sequenceNumber;

 public String getOrderId() {
  return orderId;
 }
 public void setOrderId(String orderId) {   
  this.orderId = orderId;  
 }
 public Date getOrderTime() {
  return orderTime;
 }
 public void setOrderTime(Date orderTime) {
  this.orderTime = orderTime;
 }
 public boolean isActive() {
  return isActive;
 }
 public void setActive(boolean isActive) {
  this.isActive = isActive;
 }

}

The bean above is used to describe a hypothetical warehouse order.

Now, the spring configuration file:


<?xml version="1.0" encoding="UTF-8"?>
<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"
	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">

	<!-- Use @Component annotations for bean definitions -->
	<context:component-scan base-package="it.samplespringjmx.controller" />

	<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean" />

	<!-- this bean must not be lazily initialized if the exporting is to happen -->
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
                   		<entry key="Order:name=Cart" value-ref="orderBean" />
			</map>
		</property>
		<property name="server" ref="mbeanServer" />

	</bean>

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

	<bean id="serverConnector"
		class="org.springframework.jmx.support.ConnectorServerFactoryBean">
		<property name="objectName" value="connector:name=rmi" />
		<property name="serviceUrl"
			value="service:jmx:rmi://localhost/jndi/rmi://localhost:1399/myconnector" />

		<property name="threaded" value="true" />
		<property name="daemon" value="true" />
		<property name="server">
			<ref local="mbeanServer" />
		</property>
	</bean>

	<bean id="orderBean" class="it.samplespringjmx.OrderJmx" />

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/pages/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
</beans>

Take a look at MBeanExporter bean and server connector. The first is used for exposing the orderBean to Jmx console. The second is used for connecting the Web Application with a Jmx Console. In that example the url is service:jmx:rmi://localhost/jndi/rmi://localhost:1399/myconnector.

The last code describe the spring controller of MVC.


package it.samplespringjmx.controller;

import java.util.Date;

import it.samplespringjmx.OrderJmx;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.ModelMap;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;


@Controller
public class OrderController {
 
 @Autowired
 private OrderJmx orderJmx;
 
 @RequestMapping(value="/order/{orderId}")
 public String getOrder(ModelMap model, @PathVariable String orderId) {

  if (orderJmx.isActive())
  {   
   orderJmx.setOrderId(orderId);
   orderJmx.setOrderTime(new Date());
  }
  
  model.addAttribute("detail", orderJmx);
  return "order";

 }
}

Now, it’s time to start the web server (I’m using tomcat). After this run Jconsole and connect to service:jmx:rmi://localhost/jndi/rmi://localhost:1399/myconnector. The result is on the picture below.

On the left side you can see the keys used ([Order:name=Cart])  and on the right side the properties of the bean (before this you must go to “operation” node and put setActive with value true).

Now browse the url <host>/order/CB-24233. The result is the picture below.

Another interesting feature are the Jmx Notifications.

Like raise an event, Jmx can notifying any action occured on Bean defined. Let’s go to see how it works.


package it.samplespringjmx;

import java.util.Date;

import javax.management.Notification;

import org.springframework.jmx.export.notification.NotificationPublisher;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
public class OrderJmx implements IOrderJmx,NotificationPublisherAware  {

 private String orderId;
 private Date orderTime;
 private boolean isActive;
 private NotificationPublisher publisher;
 private int sequenceNumber;

 public String getOrderId() {
  return orderId;
 }
 public void setOrderId(String orderId) {   
  this.orderId = orderId;
  
  Notification notification = new Notification("Order", this, 0, "Change OrderId");
  notification.setSequenceNumber(sequenceNumber++);
  notification.setUserData(orderId);
  
  publisher.sendNotification(notification);
  
 }
 public Date getOrderTime() {
  return orderTime;
 }
 public void setOrderTime(Date orderTime) {
  this.orderTime = orderTime;
 }
 public boolean isActive() {
  return isActive;
 }
 public void setActive(boolean isActive) {
  this.isActive = isActive;
 }
 @Override
 public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
  this.publisher = notificationPublisher;
 }

}

Look at the highlight rows; everytime the property orderId of singletone bean OrderJmx is changed, a notification will be raised.

You can see it on JConsole. On the Notification’s node click Subscribe and then browse again the <host>/order/CB-24233.

The result is on the picture.

For concluding I think It’s worth spending some hours to understand if I can use it on my next application. I described only one possible use of this technology. It can be used in many other contexts.

A good reference is in official Spring Guide (http://static.springsource.org/spring/docs/3.0.x/reference/jmx.html).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s