top of page

How to expose app. statistics by implementing JMX & view them in JConsole with namespace & grouping?

Updated: Sep 12, 2021


 

Contents

 

Today we will learn how to register MBeans with MBean Server and view them in JConsole. First a brief description about JMX , MBeans and Mbean Server is followed by how a MBean has to be created and registered in the Mbean server. Then we will also discuss how to expose application specific statistics, how to view MBean in a User Interface and how to structure MBeans with namespaces.


What is JMX?

The full name of JMX is Java Management Extensions. This Java technology provides the tools to application developers to instrument java applications so that information from the application objects, system objects, divides and network objects can be extracted during application runtime. These statistical information can then be used to monitor the health and status of the application. Java also provides RMI connectors to remotely access the statistical data extracted through JMX. Applications can be managed at runtime without redeploying. Java provided JMX connectors are used to trigger JMX operations to manage application configurations and properties. These actions can change the status of the application. JConsole is such a visualization and interaction User Interface provided by Java. See the definition of JMX in Wiki and Java Documentation for JMX technology.


What is an MBean ?

An MBean is a Java object that represents a resource like memory, CPU or any resource in the application like a cache of employee data. These Java objects are managed by the JMX technology, that is why they are called MBean(M = Managed). An MBean can have attributes that can be read or written and operations that can be invoked. The attributes and operations can be named and typed. An MBean also can have typed notifications emitted by the MBean.


As an example, if we create an application MBean to represent a configuration of a cache that holds a list of employees as master data, we can expose a few attributes of this MBean as statistics. The cache maximum size and current size could be such attributes represented by JMX attributes maxCacheSize and currentCacheSize. Writing maxCacheSize will update the maximum capacity of the cache. We can define a clear operation to delete all employee data and clear the cache. The employee MBean can send a ConfigurationChangedNotification notification when the configuration of the Mbean changes.


You can easily imagine how we can adjust application configuration as well as trigger a few operations on the application and monitor application and platform statistics in real time. In a cloud where we aim for 99% uptime the application statistics monitoring and configuration management via JMX without redeployment can be crucial. Please read the Java documentation links given above to read more about MBeans.


What is MBean Server?

MBeans have to be registered in a repository of MBeans, named MBean Server. Each Mbean must be registered with an unique name in the Mbean server. This MBean name is called ObjectName. For this reason JMX name supports domain name qualifiers like package names to provide namespaces. The MBean management applications such as JConsole access the MBeans through the MBean server.

The platform MBean server is an MBean Server that is built into Java Virtual Machine(JVM) and can be used and shared by all applications running the JVM. It is also possible to create your own MBean Server. See the Java Documentation for more on MBean Server.


How to register MBean in MBean server?

First I am going to show how to register MBeans. We are using the getPlatformMBeanServer() method of the java.lang.management.ManagementFactory to access the platform MBean server. You can read the Java documentation for know more about JMX API


The class to register MBeans

import java.lang.management.ManagementFactory;
import java.util.Set;
 
import javax.management.MBeanServer;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
 
public class CreateAndRegisterMBeanInMBeanServer {
 MBeanServer server = ManagementFactory.getPlatformMBeanServer();
 
 MyClass mbean = new MyClass();
 objectName= "the object name of the Mbean as a String";
 
 server.registerMBean(mbean, new ObjectName(objectName));
 
 Set<ObjectInstance> instances = server.queryMBeans(new ObjectName(objectName), 
              null);
  
 ObjectInstance instance = (ObjectInstance)  instances.toArray()[0];
  
 System.out.println("Class Name:t" + instance.getClassName());
 System.out.println("Object Name:t" + instance.getObjectName());
}

This class shows how to register an object as MBean , the class MyClass of the object has to be implemented as below.

  1. The class should implement an interface. The interface should be named like ClassName + "MBean". In this example MyClassMBean.

  2. The interface should have an objectName, otherwise the name of the class should be used by default.

  3. The object name should be a string but should conform with the MBean object namespace naming convention.

  4. The methods in the Bean should have the bean naming conventions. Means a field “available” that represents boolean should be named as isEdible(). A field that represents int or String should start with “get”. These will be the attributes of the JMX. the operations should be named as verbe as a convention and their return type should be void.

The MBean structures

Now I will show how to create different classes together and how to create namespaces for them.


1. The Simple JMX structure with grouping

2. The Simple JMX structure without any grouping

3. The Nested groupings


1. The simple JMX structure with grouping

First I have defined a few interfaces with the MBean object name that will appear as the name in the Jconsole. The methods with return type will be shown as MBeam attributes in the console as edible and available Count. The methods with void return type will be shown under actions for the MBean. MBean server automatically reads the JavaBean notations and does this for us, that is why we should not include any other methods in these interfaces that will not be part of MBean.

package com.myComp.myProj.jmx;
public interface PlasticMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=Mango,name=PlasticMango"; 
 boolean isEdible();
 int getAvailableCount();
 void clear();
}
 
package com.myComp.myProj.jmx;
public interface RottenMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=Mango,name=RottenMango";
 boolean isEdible();
 int getAvailableCount();
 void clear();
}
 
package com.myComp.myProj.jmx;
public interface RipeMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=Mango,name=RipeMango";
 boolean isEdible();
 int getAvailableCount();
 void clear();
}

Now I will implement these interfaces one by one. Additionally I have added the getObjectName() method which can be used to register the MBeans in the MBean Server.

package com.myComp.myProj.jmx;
public class PlasticMango implements PlasticMangoMBean { 
 int availableCount = 10;
 boolean edible = false; 
  public PlasticMango() {}
 boolean isEdible() {return edible;}
 int getAvailableCount(){return availableCount;}
 void clear() {availableCount = 0;}
 public getObjectName() { return objectName;}
}
 
package com.myComp.myProj.jmx;
public class RottenMango implements RottenMangoMBean {
 int availableCount = 20;
 boolean edible = true; 
  public RottenMango() {}
 boolean isEdible() {return edible;}
 int getAvailableCount(){return availableCount;}
 void clear()´{availableCount = 0;}
  public getObjectName() { return objectName;}
}
 
package com.myComp.myProj.jmx;
public class RipeMango implements RipeMangoMBean {
 int availableCount = 30;
 boolean edible = true; 
  public RipeMango() {}
 boolean isEdible() {return edible;}
 int getAvailableCount(){return availableCount;}
 void clear() {availableCount = 0;}
 public getObjectName() { return objectName;}
}

Look at the objectName in each interface carefully.


How to view and access the JMX?

You can view and access the JMX using JConsole. JConsole is an executable that can be found in the java installation directory. Run the above main class. Remember to run an infinite loop so that the program does not end and register the classes in the main() method as shown . Now open JConsole, go to MBean tab.

For the above coding The JMX structure will be seen as below. The namespace qualifier com.myComp.myProj.jmx will be shown as a folder. Here the presence of the namespace qualifier is exactly used for namespace purpose. There will be a subfolder under this folder, it will be named as Mango. Under this subfolder an element representing each class will be shown, these are the object names of each class. For each class you will see two attributes. The attributes are coming from the method names that have a return value; the isEdible() method that returns boolean value will be shown as boolean attribute edible. The getAvailableCount() method that returns integer value will be shown as integer attribute availableCount. Here the Mango is used to group the classes. The methods that return void will be shown as operations. There will be a button for each operation. We can trigger the code behind the void method by clicking this button. Here it’s the clear() method.

com.myComp.myProj.jmx
Mango
       PlasticMango
  Attributes
   edible
   availableCount
  Operations
   Clear
       RottenMango
  Attributes
   edible
   availableCount
  Operations
   clear
       RipeMango
  Attributes
   edible
   availableCount
  Operations
   Clear

2. The simple JMX structure without any grouping

If we do not want to group the classes in the JMX server, then we need to write the object names as below.

package com.myComp.myProj.jmx;
public interface PlasticMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=PlasticMango";
 boolean isEdible();
  int getAvailableCount();
 void clear();
}
 
package com.myComp.myProj.jmx;
public interface RottenMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=RottenMango";
 boolean isEdible();
  int getAvailableCount();
 void clear();
}
 
package com.myComp.myProj.jmx;
public interface RipeMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=RipeMango";
 boolean isEdible();
  int getAvailableCount();
 void clear();
}

The corresponding folder structure in JConsole will look like this.

com.myComp.myProj.jmx
 PlasticMango
  Attributes
   edible
   availableCount
  Operations
   clear
     RottenMango
  Attributes
   edible
   availableCount
  Operations
   clear
     RipeMango
  Attributes
   edible
   availableCount
  Operations
   clear

3. The nested groupings

We need to use the type and scope parameter to create a nested structure.

package com.myComp.myProj.jmx;
public interface PlasticMangoMBean {
 String objectName = "com.myComp.myProj.jmx:type=Mango,name=PlasticMango";
 boolean isEdible();
  int getAvailableCount();
 void clear();
}
 
package com.myComp.myProj.jmx;
public interface RottenMangoMBean {
 String objectName =
"com.myComp.myProj.jmx:type=Mango,scope="Edible",name=RottenMango";
 boolean isEdible();
  int getAvailableCount();
 void clear();
}
 
package com.myComp.myProj.jmx;
public interface RipeMangoMBean {
 String objectName = 
"com.myComp.myProj.jmx:type=Mango,scope="Edible",name=RipeMango";
 boolean isEdible();
  int getAvailableCount();
 void clear();
}

The JMX structure will be as follows. com.myComp.myProj.jmx will be the root folder. Mango will be the sub folder under the root folder. Edible will form another subfolder under Mango. The objectNmae for PlasticMango does not have a scope so it will directly come under the sub folder.

com.myComp.myProj.jmx
  Mango
  PlasticMango
   Attributes
    available
    availableCount
   Operations
    clear
 
  Edible
  RipeMango
   Attributes
    available
    availableCount
   Operations
    clear
  RottenMango
   Attributes
    available
    availableCount
   Operations
    clear
71 views0 comments

Recent Posts

See All
bottom of page