Adding the MBean to the JMX server

Part two of this tutorial delves into how and why to add MBean to the JMX server.

The JmxAgent class will be used to add the MBean to the JMX runtime. The @Component annotation is used once again on this class to instruct Spring to instantiate this class at runtime. Since there are no other classes referencing this class, the @Lazy(false) annotation instructs Spring to instantiate this class anyway, even if it's not referenced by any other spring beans. The @Autowired annotation on the MBean variable instructs Spring to look for an Application MBean implementation to pass into the JmxAgent. In our case, it will find the application class in part one.

package com.lynden.jmx;

 

import java.lang.management.ManagementFactory;

import java.util.Properties;

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.management.InstanceAlreadyExistsException;

import javax.management.MBeanRegistrationException;

import javax.management.MBeanServer;

import javax.management.MalformedObjectNameException;

import javax.management.NotCompliantMBeanException;

import javax.management.ObjectName;

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

import org.springframework.context.annotation.Lazy;

import org.springframework.stereotype.Component;

 

@Component

@Lazy(false)

public class JmxAgent {

 

protected MBeanServer mbs;

protected ObjectName objectName;

protected String appName = "";

protected String version = "";

protected String buildDate = "";

 

@Autowired

protected ApplicationMBean mbean;

 

@PostConstruct

public void connect() {

  Properties appProps = mbean.getProperties();

  appName = appProps.getProperty("app.name");

  version = appProps.getProperty("version");

 

  String name = "com.lynden." + appName + ":type=" + mbean.getClass().getName();

  mbs = ManagementFactory.getPlatformMBeanServer();

 

  try {

    objectName = new ObjectName(name);

    try {

      mbs.unregisterMBean(objectName);

    } catch (Exception ex) {

      //there may not already be a bean there to unregister.

    }

    mbs.registerMBean(mbean, objectName);

  } catch (MalformedObjectNameException |

      InstanceAlreadyExistsException |

      MBeanRegistrationException |

      NotCompliantMBeanException ex) {

    throw new RuntimeException(ex);

  }

}

 

@PreDestroy

public void disconnect() {

  if (mbs != null && objectName != null) {

    try {

      mbs.unregisterMBean(objectName);

    } catch (Exception ex) {

      //there may not be a bean there to unregister.

    }

  }

}

After the class is instantiated, Spring will call the connect method since it is annotated with the @PostConstruct annotation. This method will read the app name and version properties from the MBean so it is able to construct a unique name that will be used to reference the bean in VisualVM. The agent then attempts to unregister any old versions of the application bean and then register the new bean.

The disconnect method is called by Spring since the context shuts down, such as when the application is stopped or undeployed. The @PreDestroy annotation ensures that Spring will call the method on shutdown, and the application MBean will be unregistered from the server.

That's it! This project can then be built as a jar and used in an application to make it JMX-enabled. An example of configuring a Web application to use this new functionality follows.

Using the application MBean in a Web application

For the second part of this tutorial, we'll add the SampleJmxUtils library created above to a new JmxDemoWebProject, which will run in a Glassfish application server.

Using the application MBean above is a very straightforward task. First, the target application must have the Spring libraries available. If you are using Maven, simply adding the SampleJmxUtils project as a dependency to the JmxDemoWebProject will be enough to bring the Spring dependencies forward. The "spring-web.jar" will be an additional dependency that will need to be added to the project.

Assuming the project has not already been configured to use Spring, the following lines need to be added to the web.xml file in order to start the Spring context when the application is loaded. This assumes that the application's beans.xml (detailed below) file lives in the application's WEB-INF/classes directory.

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

<context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>/WEB-INF/classes/beans.xml</param-value>

</context-param>

 

<!-- Creates the Spring Container shared by all Servlets and Filters -->

<listener>

  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

The last task is to then add 2 lines to the beans.xml file in your project, which will instruct Spring to scan the com.lynden.jmx package for any beans, at which point it will find both the application MBean as well as the JmxAgent class. The beans.xml file for this particular project is kept in the applications WEB-INF/classes directory.

  <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="https://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">

 

  <context:annotation-config/>

  <context:component-scan base-package="com.lynden.jmx" />

 

</beans>

That's all that needs to happen in order to make this Web application JMX enabled with the base functionality of the application MBean.

More on this tutorial:
Monitor your Web apps with JMX and Spring

Configure VisualVM to connect to the app server

How to make MBean work

Dig Deeper on Front-end, back-end and middle-tier frameworks