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应用的场景并不多,正所谓:利器深藏之而不用,非常时方现光芒。