JMX的Dynamic MBean不需要自定义MBean接口,只需要实现JDK提供的DynamicMBean接口即可。Dynamic MBean没有任何明显写在代码里的属性和方法,所有的属性和方法都是通过反射结合JMX提供的辅助元数据,从而动态生成的。
Dynamic MBean:
package com.jmx.dynamic.demo;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.DynamicMBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;
public class HelloDynamic implements DynamicMBean {
//attributes
private String name;
private MBeanInfo mBeanInfo = null;
private String className;
private String description;
private MBeanAttributeInfo[] attributes;
private MBeanConstructorInfo[] constructors;
private MBeanOperationInfo[] operations;
MBeanNotificationInfo[] mBeanNotificationInfoArray;
public HelloDynamic() {
init();
buildDynamicMBean();
}
private void init() {
className = this.getClass().getName();
description = "Simple implementation of a MBean.";
//initial attributes
attributes = new MBeanAttributeInfo[1];
//initial constructors
constructors = new MBeanConstructorInfo[1];
//initial method
operations = new MBeanOperationInfo[1];
mBeanNotificationInfoArray = new MBeanNotificationInfo[0];
}
private void buildDynamicMBean() {
//create constructor
Constructor[] thisconstructors = this.getClass().getConstructors();
constructors[0] = new MBeanConstructorInfo("HelloDynamic(): Constructs a HelloDynamic object", thisconstructors[0]);
//create attribute
attributes[0] = new MBeanAttributeInfo("Name", "java.lang.String", "Name: name string.", true, true,false);
//create operate method
MBeanParameterInfo[] params = null;//no parameter
operations[0] = new MBeanOperationInfo("print", "print(): print the name", params, "void", MBeanOperationInfo.INFO);
//create mbean
mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
}
//dynamically add a print1 method
private void dynamicAddOperation() {
init();
operations = new MBeanOperationInfo[2];
buildDynamicMBean();
operations[1] = new MBeanOperationInfo("print1", "print1(): print the name", null, "void", MBeanOperationInfo.INFO);
mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
}
@Override
public Object getAttribute(String attribute_name) {
if (attribute_name == null) {
return null;
}
if (attribute_name.equals("Name")) {
return name;
}
return null;
}
@Override
public void setAttribute(Attribute attribute) {
if (attribute == null) {
return;
}
String Name = attribute.getName();
Object value = attribute.getValue();
try {
if (Name.equals("Name")) {
// if null value, try and if the setter returns any exception
if (value == null) {
name = null;
// if non null value, make sure it is assignable to the attribute
} else if ((Class.forName("java.lang.String")).isAssignableFrom(value.getClass())) {
name = (String) value;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public AttributeList getAttributes(String[] attributeNames) {
if (attributeNames == null) {
return null;
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, return anempty result list
if (attributeNames.length == 0) {
return resultList;
}
for (int i = 0; i < attributeNames.length; i++) {
try {
Object value = getAttribute(attributeNames[i]);
resultList.add(new Attribute(attributeNames[i], value));
} catch (Exception e) {
e.printStackTrace();
}
}
return resultList;
}
@Override
public AttributeList setAttributes(AttributeList attributes) {
if (attributes == null) {
return null;
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, nothing more to do
if (attributes.isEmpty()) {
return resultList;
}
// for each attribute, try to set it and add to the result list if successfull
for (Iterator i = attributes.iterator(); i.hasNext();) {
Attribute attr = (Attribute) i.next();
try {
setAttribute(attr);
String name = attr.getName();
Object value = getAttribute(name);
resultList.add(new Attribute(name, value));
} catch (Exception e) {
e.printStackTrace();
}
}
return resultList;
}
@Override
public Object invoke(String operationName, Object params[], String signature[]) throws MBeanException,ReflectionException {
// Check for a recognized operationname and call the corresponding operation
if (operationName.equals("print")) {
System.out.println("Hello, " + name + ", this is HelloDynamic!");
//dynamic add a method
dynamicAddOperation();
return null;
} else if (operationName.equals("print1")) {
System.out.println("dynamically add a print1 method");
return null;
} else {
// unrecognized operation name:
throw new ReflectionException(new NoSuchMethodException(operationName), "Cannot find the operation " + operationName + " in " + className);
}
}
public MBeanInfo getMBeanInfo() {
return mBeanInfo;
}
}
package com.jmx.dynamic.demo;
import java.lang.management.ManagementFactory;
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 com.sun.jdmk.comm.HtmlAdaptorServer;
public class HelloAgent {//as same as standard mbean
public static void main(String[] args) throws MalformedObjectNameException, NullPointerException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
//create mbean server
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
//create object name
ObjectName helloName = new ObjectName("jmx:name=dynamicBeanHello");
//create mbean and register mbean
server.registerMBean(new HelloDynamic(), helloName);
//create adaptor, adaptor is just a form as show mbean. It has no relation to specific mbean.
HtmlAdaptorServer adaptor = new HtmlAdaptorServer();
//create adaptor name
ObjectName adaptorName = new ObjectName("jmxAdaptor:name=adaptor,port=5050");
//register adaptor and adaptor name
server.registerMBean(adaptor, adaptorName);
adaptor.setPort(9999);
adaptor.start();
System.out.println("....................jmx server start....................");
}
}
点击我们在JMXServer上注册的Dynamic MBean
可以看到动态生成的属性和方法:
点击print方法后,控制台输出如下:
再返回MBean View,可以看到又动态创建了一个print1方法:
Dynamic MBean应用的场景并不多,正所谓:利器深藏之而不用,非常时方现光芒。