Here's a simple application that illustrates exposing internals using JMX.

Description

Application contains:

  • Web deployment descriptor (e.g. WEB-INF/web.xml) that describes the application (optional)
  • JSP views: home.jsp and WEB-INF/views/view.jsp
  • A counter (e.g. example.jmx.web.MyCounter) that can increment, get current count, reset counter and reset to a specific value.
  • A servlet (e.g. example.jmx.web.CounterServlet) that calls counter and forwards to a view (e.g. WEB-INF/views/view.jsp)
  • A servlet listener (e.g. example.jmx.web.RegisterMBeansListener), that registers the MBean to JMX MBeanServer
  • An MBean interface (e.g. example.jmx.mbean.CounterMBean) that defines JMX attributes and operations, e.g. name, resetCounter, getCurrentCount, getCurrentTime
  • An MBean implementation (e.g. example.jmx.mbean.Counter) that implements MBean interface

Code Examples

example.jmx.web.MyCounter

package example.jmx.web;

import java.util.concurrent.atomic.AtomicInteger;

public class MyCounter {

    private static AtomicInteger counter = new AtomicInteger(0);
    
    public static int incrementAndGet() {
        return counter.incrementAndGet();
    }
    
    public static int getCurrentCount() {
        return counter.get();
    }
    
    public static void resetCounter() {
        resetCounter(0);
    }
    
    public static void resetCounter(int start) {
        counter = new AtomicInteger(start);
    }

}

example.jmx.web.CounterServlet servlet

package example.jmx.web;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/count")
public class CounterServlet extends HttpServlet {

    private static final long serialVersionUID = 886395215542306826L;
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setAttribute("COUNT", MyCounter.incrementAndGet());
        request.getRequestDispatcher("/WEB-INF/views/view.jsp").forward(request, response); 
    }

}

example.jmx.web.RegisterMBeansListener web listener

package example.jmx.web;

import java.lang.management.ManagementFactory;

import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import example.jmx.mbean.CounterMBean;
import example.jmx.mbean.Counter;

@WebListener
public class RegisterMBeansListener implements ServletContextListener {

    private ObjectName objectName;

    public RegisterMBeansListener() {
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Registering MBean...");
        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        try {
            objectName = new ObjectName("JmxExampleApp:type=Counter");
            final CounterMBean mbean = new Counter();
            server.registerMBean(mbean, objectName);
            System.out.println("MBean registered: " + objectName);
        } catch (MalformedObjectNameException mone) {
            mone.printStackTrace();
        } catch (InstanceAlreadyExistsException iaee) {
            iaee.printStackTrace();
        } catch (MBeanRegistrationException mbre) {
            mbre.printStackTrace();
        } catch (NotCompliantMBeanException ncmbe) {
            ncmbe.printStackTrace();
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Unregistering MBean...");
        final MBeanServer server = ManagementFactory.getPlatformMBeanServer();
        try {
            objectName = new ObjectName("JmxExampleApp:type=Counter");
            server.unregisterMBean(objectName);
            System.out.println("MBean unregistered: " + objectName);
        } catch (MalformedObjectNameException mone) {
            mone.printStackTrace();
        } catch (MBeanRegistrationException mbre) {
            mbre.printStackTrace();
        } catch (InstanceNotFoundException infe) {
            infe.printStackTrace();
        } 
    } 
  
}

example.jmx.mbean.CounterMBean interface

package example.jmx.mbean;

import java.util.Date;

public interface CounterMBean {
    void resetCounter();
    void resetCounter(int start);
    int getCurrentCount();
    Date getCurrentTime();
    long getCurrentTimeMilis();
}

example.jmx.mbean.Counter implementation

package example.jmx.mbean;

import java.util.Date;

import example.jmx.web.MyCounter;

public class Counter implements CounterMBean {

    private String name;
    
    public Counter() {
        this.name = "InitialName";
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Override
    public void resetCounter() {
        MyCounter.resetCounter();
    }

    @Override
    public void resetCounter(int start) {
        MyCounter.resetCounter(start);
    }
    
    @Override
    public int getCurrentCount() {
        return MyCounter.getCurrentCount();
    }
    
    @Override
    public Date getCurrentTime() {
        return new Date();
    }
    
    @Override
    public long getCurrentTimeMilis() {
        return System.currentTimeMillis();
    }

}

Download

Download JmxExample.war (with source code).

  • No labels