一、简介
Model MBean是基于DynamicMBean的更实用的MBean,如果编写被管理的类为标准MBean,我们必须为它们实现一套以MBean为后缀名的接口,这样使代码的耦合度增高。而基于Model Mbean,我们可以用配置文件等动态的方式来管理类,被管理的类可以是普通的类,这样也降低了系统的耦合性。
二、准备工作
1、为了Web方式管理MBean,我们引入jmxtools.jar
三、代码实例
package com.muyu.jmx; public class ConfigModel { private String configLocation; public String getConfigLocation() { return configLocation; } public void printConfigLocation() { System.out.println(configLocation); } public void printConfigLocation(String i_ConfigLocation) { System.out.println(i_ConfigLocation); } public void setConfigLocation(String configLocation) { this.configLocation = configLocation; } }
package com.muyu.jmx; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import javax.management.modelmbean.RequiredModelMBean; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import com.sun.jdmk.comm.HtmlAdaptorServer; public class ConfigAgent { public static void main(String[] args) throws Exception { MBeanServer server = MBeanServerFactory.createMBeanServer(); ObjectName configName = new ObjectName("LuisFigo:name=configModel"); RequiredModelMBean config = ModelMBean.createModelMBean(); server.registerMBean(config, configName); ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8000"); //通过Web来管理MBean HtmlAdaptorServer adapter = new HtmlAdaptorServer(); adapter.setPort(8000); server.registerMBean(adapter, adapterName); adapter.start(); System.out.println("adapter start....."); //通过RMI方式来管理MBean Registry registry = LocateRegistry.createRegistry(9999); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/mserver"); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server); cs.start(); System.out.println("rmi start....."); } }
package com.muyu.jmx; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.Descriptor; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.management.MBeanException; import javax.management.MBeanParameterInfo; import javax.management.ReflectionException; import javax.management.RuntimeOperationsException; import javax.management.modelmbean.DescriptorSupport; import javax.management.modelmbean.InvalidTargetObjectTypeException; import javax.management.modelmbean.ModelMBeanAttributeInfo; import javax.management.modelmbean.ModelMBeanInfo; import javax.management.modelmbean.ModelMBeanInfoSupport; import javax.management.modelmbean.ModelMBeanOperationInfo; import javax.management.modelmbean.RequiredModelMBean; public class ModelMBean { private static final boolean READABLE = true; private static final boolean WRITABLE = true; private static final boolean IS = true; private final static String STRING_CLASS = "java.lang.String"; public static RequiredModelMBean createModelMBean() throws RuntimeOperationsException, MBeanException, InstanceNotFoundException, InvalidTargetObjectTypeException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException { RequiredModelMBean modelMBean = null; modelMBean = new RequiredModelMBean(); modelMBean.setManagedResource(new ConfigModel(), "ObjectReference"); ModelMBeanInfo info = createModelMBeanInfo(); modelMBean.setModelMBeanInfo(info); modelMBean.setAttribute(new Attribute("ConfigLocation", "test initial")); return modelMBean; } public static ModelMBeanInfo createModelMBeanInfo() { Descriptor portAttrDesc = new DescriptorSupport(); portAttrDesc.setField("name", "ConfigLocation"); portAttrDesc.setField("descriptorType", "attribute"); portAttrDesc.setField("displayName", "ConfigLocation"); portAttrDesc.setField("getMethod", "getConfigLocation"); portAttrDesc.setField("setMethod", "setConfigLocation"); //属性 ModelMBeanAttributeInfo nameAttrInfo = new ModelMBeanAttributeInfo("ConfigLocation", // 属性名 STRING_CLASS, //属性类型 "luisfigo location", // 描述文字 READABLE, WRITABLE, !IS, // 读写 portAttrDesc ); //方法 Descriptor getStateDesc = new DescriptorSupport(new String[] { "name=getConfigLocation", "descriptorType=operation", "class=com.muyu.jmx.ConfigModel", "role=operation" }); // 构造 setConfigLocation操作描述符信息 Descriptor setStateDesc = new DescriptorSupport(new String[] { "name=setConfigLocation", "descriptorType=operation", "class=com.muyu.jmx.ConfigModel", "role=operation" }); ModelMBeanOperationInfo getConfigLocation = new ModelMBeanOperationInfo( "getConfigLocation", "get configLocation attribute", null, "java.lang.String", ModelMBeanOperationInfo.ACTION, getStateDesc ); MBeanParameterInfo[] setStateParms = new MBeanParameterInfo[] { (new MBeanParameterInfo( "configLocation_para", "java.lang.String", "new configLocation value")) }; ModelMBeanOperationInfo setConfigLocation = new ModelMBeanOperationInfo( "setConfigLocation", "set configLocation attribute", setStateParms, "void", ModelMBeanOperationInfo.ACTION, setStateDesc ); ModelMBeanOperationInfo printConfig = new ModelMBeanOperationInfo("printConfigLocation", "控制台输出configLocation信息", null, "void", ModelMBeanOperationInfo.INFO, null); ModelMBeanOperationInfo printConfig_1 = null; MBeanParameterInfo[] params = new MBeanParameterInfo[1]; params[0] = new MBeanParameterInfo("i_ConfigLocation", STRING_CLASS, "Hello , I am LuisFigo"); printConfig_1 = new ModelMBeanOperationInfo("printConfigLocation", "控制台输出configLocation_para信息", params, "void", ModelMBeanOperationInfo.INFO, null); ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(// RequiredModelMBean.class.getName(), // MBean类 "ModelMBeanInfoSupport Dynamic MBean", // 描述文字 new ModelMBeanAttributeInfo[] { // 所有的属性信息(数组) nameAttrInfo },//只有一个属性 null, // 所有的构造函数信息 new ModelMBeanOperationInfo[] { // 所有的操作信息(数组) getConfigLocation, setConfigLocation, printConfig, printConfig_1},// null, null ); return mbeanInfo; } }
package com.muyu.jmx; import java.io.IOException; import java.util.Iterator; import java.util.Set; import javax.management.Attribute; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.InvalidAttributeValueException; import javax.management.MBeanException; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.ReflectionException; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class ConfigClient { public static void main(String[] args) throws IOException, MalformedObjectNameException, NullPointerException, InstanceNotFoundException, MBeanException, ReflectionException, AttributeNotFoundException, InvalidAttributeValueException { JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/mserver"); JMXConnector jmxc = JMXConnectorFactory.connect(url, null); MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); Set names = mbsc.queryNames(null, null); for (Iterator i = names.iterator(); i.hasNext();) { System.out.println("\tObjectName = " + (ObjectName) i.next()); } ObjectName stdMBeanName = new ObjectName("LuisFigo:name=configModel"); mbsc.invoke(stdMBeanName, "printConfigLocation", new String[]{"helloworld"}, new String[]{"java.lang.String"}); mbsc.setAttribute(stdMBeanName, new Attribute("ConfigLocation", "LuisFigo, this is a new configLocation")); mbsc.invoke(stdMBeanName, "printConfigLocation", null, null); jmxc.close(); } }
说明:
运行ConfigAgent后,在浏览器里输入地址http://localhost:8000/,点击name=configModel后进行configModel MBean管理页面,可以对configMBean进行一些操作,同第二节介绍的标准MBean很相似。运行ConfigClient可以发现,通过RMI可以管理ConfigAgent中注册的MBean。
四、总结
动态ModelMBean实现了被管理类与JMX的解耦,在ModelMBean类里我们可以暴露一些操作和属性。而客户端看起来像什么事都没有发生一样。如果采用JMX来管理系统的话,我们只需要提供一个ModelMBean这样一个管理类就可以,而不需要破坏原来的系统代码,真正实现了系统与JMX的解耦。