复习
一共有四种MBean:
动态MBean是在运行期才定义它的属性和方法,也就是说它有什么属性和方法是可以动态改变的。
动态MBean主要利用一些辅助类(构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类MBeanOperationInfo)来完成这个功能,所有的动态MBean必须实现DynamicMBean接口。
DynamicMBean写好后,使用方法和第一篇文章中普通的MBean一样。
1)编写动态MBean
public class HelloDynamic implements DynamicMBean { //这是我们的属性名称 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 dynamic MBean."; attributes = new MBeanAttributeInfo[1]; constructors = new MBeanConstructorInfo[1]; operations = new MBeanOperationInfo[1]; mBeanNotificationInfoArray = new MBeanNotificationInfo[0]; } private void buildDynamicMBean() { //设定构造函数 Constructor[] thisconstructors = this.getClass().getConstructors(); constructors[0] = new MBeanConstructorInfo( "HelloDynamic(): Constructs a HelloDynamic object", thisconstructors[0]); //设定一个属性 attributes[0] = new MBeanAttributeInfo( "Name", "java.lang.String", "Name: name string.", //String description, true, true, false); //boolean isReadable,boolean isWritable,boolean isIs //operate method 我们的操作方法是print MBeanParameterInfo[] params = null;//无参数 operations[0] = new MBeanOperationInfo( "print", "print(): print the name", //String description, params, "void", MBeanOperationInfo.INFO); mBeanInfo = new MBeanInfo( className, description, attributes, constructors, operations, mBeanNotificationInfoArray); } //动态增加一个print1方法 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 see 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 an empty 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 operation name and call the corresponding operation if (operationName.equals("print")) { //=======具体实现我们的操作方法print ======= System.out.println("Hello, " + name + ", this is HellDynamic!"); dynamicAddOperation(); System.out.println("added a dynamic operation(print1)!"); return null; } else if (operationName.equals("print1")) { System.out.println("这是动态增加的一方法print1"); return null; } else { // unrecognized operation name: throw new ReflectionException(new NoSuchMethodException(operationName), "Cannot find the operation " + operationName + " in " + className); } } @Override public MBeanInfo getMBeanInfo() { return mBeanInfo; } }
前面说了HelloDynamic和普通MBean的使用方法是一样的,因此HelloAgent和第一篇的HelloAgent基本一样,就是把Hello改成HelloDynamic而已。
public class HelloAgent { public static void main(String[] args) throws Exception { //先创建了一个MBeanServer,用来做MBean的容器 // MBeanServer server = MBeanServerFactory.createMBeanServer(); MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName helloName = new ObjectName("alpha-dynamic:name=HelloWorld"); HelloDynamic hello=new HelloDynamic(); //将Hello这个类注入到MBeanServer中,注入需要创建一个ObjectName类 server.registerMBean(hello, helloName); //创建一个AdaptorServer,这个类将决定MBean的管理界面,这里用最普通的Html型界面。AdaptorServer其实也是一个MBean。 // alpha:name=HelloWorld的名字是有一定规则的,格式为:“域名:name=MBean名称”,域名和MBean名称都可以任意取。 ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082"); HtmlAdaptorServer adapter = new HtmlAdaptorServer(); server.registerMBean(adapter, adapterName); adapter.start(); System.out.println("start....."); } }
3)运行
先运行HelloAgent。
再打开浏览器,输入网址:http://localhost:8082/。单击进入“name=HelloDynamic ”项,执行print方法后再回到上一页面你会发现又多了一个print1方法。
start..... Hello, null, this is HellDynamic! added a dynamic operation(print1)! 这是动态增加的一方法print1
4)总结
动态MBean的代码稍显复杂,但对于一些特殊需求的情况,它将显示出强大威力。而且它还是模型MBeans(Model MBeans)的基础。不过在一般的项目中,动态MBean还是用得比较少,所谓利器深藏之而不用,非常时方现光芒。