Home > tech > Using JMX for Managing Application Properties in Production

Using JMX for Managing Application Properties in Production

September 29th, 2010 Leave a comment Go to comments

JEE web applications that use the Spring container typically use property files for configuring the application for different customers, resources or boundary conditions. The property file is either read by a utility class or used by Spring’s popular PropertyPlaceholderConfigurer class to substitute properties in the spring application context at runtime.

When an application is deployed, the properties are (typically) loaded in the JVM in some sort of cache at startup and then used throughout the life of the application. Most applications provide a UI to manipulate the properties in production but more often than not, UI development cannot keep up with the rate at which properties are added to the application. The application is deployed and before long it becomes necessary to change a property value in production.. but.. oops.. no UI! The only option left is to change the property, rebuild and redeploy, which, of course means an outage for the users.

That’s when this relatively easy method of manipulating application properties via JMX at runtime may be useful. Using Spring JMX, we will expose  properties to a controlled set of users so that they can be read and written to.

Broadly, the steps are:

  1. Implement the DynamicMBean interface to expose all the properties in an application as attributes.
  2. Start the MBean server on Tomcat
  3. Expose that implementation using Spring JMX and deploy the application.
  4. Use JConsole to access the MBean Server implementation and manipulate the values of the properties.

Let’s look at each in turn:

Implement DynamicMBean

Spring JMX has made it extremely easy to expose a bean via JMX. Through Spring’s proxy mechanism, we can expose any Spring managed bean as a Managed Bean. The bean does not even have to implement the MBean interface. However, if we are using Spring’s interface proxies (as against class based proxies), it may be a good idea to have the managed bean implement some interface.

Additionally, if  it is necessary to transport data back to the JMX Client, then using an MXBean may be a better approach. (See here for a comparison of MBean to an MXBean).

For what we are trying to do here, we need to expose an arbitrary number of properties in the JMX client. The number (and names) of properties is not known at compile time;  the JMX specification provides the DynamicMBean interface where the interface (to be exposed) is defined at runtime.

Let’s begin by defining a business interface like so:

public interface ManageableProperties{
	public Properties getProperties();
	public Collection getHiddenPropertiesList();
        public Collection getReadOnlyPropertiesList();
}

This ‘business’ aspect of this interface tells the JMX client what properties need exposed, what properties are hidden and what are read-only.

Then define the class that is going to be managed via JMX and make that class implement the ManageableProperties interface.

public class JMXPropertyManager implements ManageableProperties {
	@Override
	public Properties getProperties(){
		return (Properties)AcmePropertyManager.getProperties();
	}
	@Override
	public Collection<String> getHiddenPropertiesList() {
		Collection<String> c = new ArrayList<String>();
		c.add("acme.db.password");
		return c;
	}
	@Override
	public Collection<String> getReadOnlyPropertiesList() {
		Collection<String> c = new ArrayList<String>();
		c.add("acme.allowConcurrentUsers");
		return c;
	}
}

Here the implementation of the interface is specifying what properties should be hidden (after all, you may not want to expose all properties in your application for administration), and what properties should be read-only.

Finally, let’s introduce the DynamicMBean interface to the same class (JMXPropertyManager). Doing that adds the following code:

private Properties properties;

public JMXPropertyManager(){
	properties = this.getProperties();
}
private boolean isHidden(String key){
    	boolean boo = false;
    	Collection hiddenList = this.getHiddenPropertiesList();
    	for (String string : hiddenList) {
		if (key.equalsIgnoreCase(string)){
			boo = true;
			break;
		}
	}
    	return boo;
}
private boolean isReadOnly(String key){
    	boolean boo = false;
    	Collection roList = this.getReadOnlyPropertiesList();
    	for (String string : roList) {
		if (key.equalsIgnoreCase(string)){
		        boo = true;
			break;
		}
	}
    	return boo;
}
@Override
public MBeanInfo getMBeanInfo() {
    MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[properties.size()];
    MBeanInfo mBeanInfo = null;
    MBeanOperationInfo[] operations = new MBeanOperationInfo[1];
    int i = 0;
    for (Iterator iterator = properties.keySet().iterator(); iterator.hasNext();) {
	String key = (String) iterator.next();
        if (this.isReadOnly(key) || isHidden(key)){
		attributes[i] = new MBeanAttributeInfo
                     (key, "java.lang.String", key, true, false, false);
        } else {
		attributes[i] = new MBeanAttributeInfo
                     (key, "java.lang.String", key, true, true, false);
	}
        i++;
     }
     operations[0] = new MBeanOperationInfo("refreshCache", "Refresh Caches", null , null, MBeanOperationInfo.ACTION);
     mBeanInfo = new MBeanInfo(this.getClass().getName(),
            "Manage Properties", attributes, null,  operations, null);
     return mBeanInfo;
}
@Override
public Object getAttribute(String attribute) throws AttributeNotFoundException,
               MBeanException, ReflectionException {
        Object o = null;
        if (isHidden(attribute)) {
            o = "XXX-HIDDEN-VALUE-XXX";
        } else {
            o =  properties.get(attribute);
        }
	return o;
}
@Override
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
           InvalidAttributeValueException, MBeanException, ReflectionException {
    String key = attribute.getName();
    String value = (String)attribute.getValue();
    properties.put(key, value);
}
@Override
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
     Object ret = null;
     if (actionName == null){
       throw new RuntimeOperationsException( new IllegalArgumentException( "Operation name cannot be null"), "Cannot invoke a null operation");
     }
     if (actionName.equals("refreshCache")){
         AcmePropertyManager.refreshCache();
     }
    //Returning null because we would like to avoid passing back a complex object
    //to the JMXClient because we have not implemented a MXBean
    return ret;
}

//---other unimplemeted methods of the DynamicMBean interface------

Here is where most of the action happens: The getMBeanInfo method creates a MBeanInfo object that has all the attributes (hidden, non-hidden, read-only and writable) defined. The In addition, an operation called refreshCaches is also defined.

Start the MBean server on Tomcat

Starting Tomcat with JMX enabled is explained here.

Deploying to a MBean Server

Thank God for Spring JMX! Deploying to an existing MBean Server was never easier! Just add the following to you Spring context:

    <!-- this bean must not be lazily initialized if the exporting is to happen -->
    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="beans">
      <map>
        <entry key="bean:name=acmeProperties" value-ref="jmxPropertyManager"/>
      </map>
    </property>
    </bean>

    <bean id="jmxPropertyManager" class="com.acme.JMXPropertyManager">
    </bean>

Assuming that you are deploying your application to an application server that has an inbuilt (exactly one) MBeanServer, such at Tomcat, that’s all there is to it! The JMXPropertyManager is now available as a MBean as seen in the picture below.

Use JConsole to access the MBean Server

Accessing a Tomcat JMX Server is explained here.

Clicking on the bean | acmeProperties node shows us:

We see that the properties that are masked and read-only in our ‘business’ interface, ManegableProperties,  correctly behave as specified.

That’s it. Have fun managing application properties in production!

If you like what you read, share what you like!
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • RSS
  • Technorati
  • DZone
  1. kishore maddi
    January 10th, 2011 at 19:40 | #1

    Hi,

    I implemented this code in my application. I changed the code according to my application. The thing is i am able to change my property values through jconsole. But those values are not impacting in running server. Please advise me.

    Thanks,
    Kishore maddi.

  2. pankaj
    January 10th, 2011 at 20:47 | #2

    Hi Kishore,
    Glad that you were able to use this technique to change properties in your app. As far as the values not “impacting in running server”, I am assuming that the changed properties are not being seen by your app. For that, I can only say that all this technique is doing is changing properties in the JVM, in the heap of your server; how that is used in the app depends on the app really. For instance, if you are holding a second level cache in your app, then these changed values will not show up there.
    Having said that, I’ll also mention that you can use the same technique to call business level methods on your services. See the other post I have called “Adding Aspects in a Running Web Application” (http://nayidisha.com/techblog/adding-aspects). That shows you how to call a business method. Maybe you can use that to “impact your server”.

    Hope that helps!
    Pankaj

  3. May 1st, 2012 at 17:51 | #3

    Is your Rss url working properly? I cannot find a way to join for your main feed for some reason, however the responses feed works flawlessly?

  4. June 27th, 2012 at 23:01 | #4

    Have you had problems with spammers? I also use Blog Engine and I have some good anti-spam techniques; please Email me if you are interested in an exchange of ideas. Cos come pi facile avere risposta rapida alla domanda Hey, quale editor grafico per il Mac. via Twitter che dal collega che lavora alla scrivania di fronte.

  5. jai
    August 16th, 2012 at 08:50 | #5

    Where I can get the “AcmePropertyManager” code/or the complete source?

    Few questions where I am looking for an answer for my implementation:

    1. I have a few properties file, and I would like to manipulate the value via console
    (rather than updating (by means of any I/O operation) the K/V pair back to the same property file), so that the respective app change its behaviour. Any pointers on this.

    2. I would like to show certain property from the properties file (not all) into the console. Which approach would be better: MBeans or DynamicMbeans and how?

    Thanks.

  6. Anonymous
    August 17th, 2012 at 10:05 | #6

    @jai
    Well … I manage to get huge progress into this. Thanks for the entry.
    One question, when I refresh the cache, the property are not getting set to the older values. Why?

  7. Anonymous
    August 17th, 2012 at 10:07 | #7

    Well … I manage to get huge progress into this. Thanks for the entry.
    One question, when I refresh the cache, the property are not getting set to the older values into the JMX console. Why?

  8. Gangadhar Methari
    November 28th, 2013 at 07:06 | #8

    Hi,

    I have written simple Spring-JMX program which has the capability to change logging of existing application from Jconsole but when i deployed it to the web/app server the Jconsole not shwoing my Mbean. Can you please give me the sample code for the application which should run individually and accessing the exising/ running application by accepting the server details.

    Thanks,
    Gangadhar

  9. Gangadhar Methari
    November 28th, 2013 at 07:10 | #9

    @kishore maddi
    Hi Kishore,
    I am new to Spring-JMX and spent almost couple of days to cracking this one but no luck am struck up with some thing need your help, If you dont mind can u please post/ send to my mail id(metari.gangadhar@gmail.com) your code so that i can re-use and and implement some customizations to that one.

    Thanks,
    Gangadhar

  1. November 9th, 2010 at 17:59 | #1

Get Adobe Flash playerPlugin by wpburn.com wordpress themes