JMX架构的了解 (MBean部分)

板桥里人 https://www.jdon.com 2003/1/5

我们前章举例的HelloMBean是StandardMBean,这是JMX中的MBean的一种,还有一种 叫DynamicMBean,这是JMX在运行期间能够控制它, 无论哪种MBean,他们的区别只是在他们如何被开发,而不是在它们如何被管理, JMX的Agent提供了处理这两种类型的抽象的处理方法,也就是说,一旦这两种MBean 被JMX的Agent管理,这两种MBean在外界看来没什么区别。

一个标准的standard MBean的Java class是通过它的attributes和operations 被外界管理的,Attributes是内部的一些属性变量,它通过getter 和 setter方法被外界管理 在HelloMBean中,它们是

public String getName();
public void setName(String name);

Operations 是这个class中其它愿意被管理的方法,在HellMBean中是
public void print()

所有这些方法需要在MBean接口中定义,然后通过introspection(内省机制) 显露给一个agent, 上述方法是制造一个可管理资源的最直接办法。

DynamicMBean

而在开发一个DynamicMBean时,attributes 和operations是通过方法调用 间接的显露给agent的。DynamicMBean 适合管理那些已经存在的资源和代码。

需要被JMX的Agent认为是 DynamicMBean,这个Java class或它的子类必须继承 一个DynamicMBean的标准接口。

getMBeanInfo:
DynamicMBean不象StandardMBean那样通过introspection(内省机制)向外界 显露他的attributes和operations,而是通过在运行时,返回这个方法的值来向 外界显露他的attribute names 和 types 以及 operation signatures 。 这个方法返回的是MBeanInfo实例.

getAttribute 和 getAttributes

这是获得相应的attribute name属性名称或属性名称表的值,这个类似StandardMBean的 getter方法,不同点是由调用者提供所需要的属性名,如 public Object getAttribute(String attribute_name) 不同于StandardMBean的getXXXX(Attribute_name)。

setAttribute 和 setAttributes

这个类似StandardMBean的setter方法, 设置相应属性的name-value对。

invoke

invoke方法是让外界来调用DynamicMBean的操作,这儿调用者必须提供 操作名称 作为参数传递的object和这些参数的类型,具体如: public Object invoke(String operationName, Object params[], String signature[])

当DynamicMBean在JMX agent中注册后,DynamicMBean其实就和StandardMBean 是一样的,外界将首先通过getMBeanInfo获得一个管理接口,其中包含attributes 和 operations 名称,然后才将调用DynamicMBean的getters, setters 和invoke方法,

MBean原始类

从上面可以看到,MBean有一些自己规定的诸如MBeanInfo这样的原始类,一共有如下几种:

MBeanInfo - 罗列出所有的属性attribute, 操作operations, 构造器constructor 和 notification

MBeanFeatureInfo - 下面类的子类

MBeanAttributeInfo - 描述一个属性attribute

MBeanConstructorInfo - 描述一个构造器constructor MBean构造器是由签名单独地定义,这个签名是参数的次序和类型.

MBeanOperationInfo - 描述一个操作operation

MBeanParameterInfo - 描述一个操作或构造器的参数

MBeanNotificationInfo - 描述一个notification

通过与使用这些原始类,将你的具体资源就可以动态的嵌入DynamicMBean了.

我们看看下面HelloDynamic程序是如何使用这些原始类构成一个DynamicMBean的:

我们还以上章中的Hello为例,Hello是以Standard MBean来实现了对name的赋值和打印功能.那么通过使用Dynamic MBean我们也来实现这个功能,在这个资源中,有一个属性name以及操作方法print.下面示例展示如何将这个属性和这个操作方法使用DynamicMBean的原始类来实现:

//
import javax.management.*;
import java.lang.reflect.Constructor;
import java.util.Iterator;

/**
* @author Sunny Peng
* @version 1.0
*/

public class HelloDynamic
implements DynamicMBean {

//这是我们的属性名称
private String name = "";

private MBeanInfo mBeanInfo = null;
private String className = this.getClass().getName();
private String description = "Simple implementation of a dynamic MBean.";

private MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[1];
private MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[1];
private MBeanOperationInfo[] operations = new MBeanOperationInfo[1];
MBeanNotificationInfo[] mBeanNotificationInfoArray = new
MBeanNotificationInfo[0];

public HelloDynamic() {

  //设定一个属性
  attributes[0] = new MBeanAttributeInfo("Name",
  "java.lang.String",
  "Name: name string.",
  true,
  true,
  false);

  //设定构造函数
  Constructor[] thisconstructors = this.getClass().getConstructors();
  constructors[0] = new MBeanConstructorInfo(
  "HelloDynamic(): Constructs a HelloDynamic object",
  thisconstructors[0]);

  //operate method 我们的操作方法是print
  MBeanParameterInfo[] params = null;
  operations[0] = new MBeanOperationInfo("print",
  "print(): print the name",
  params,
  "void",
  MBeanOperationInfo.INFO);

  mBeanInfo = new MBeanInfo(className, description, attributes,
  constructors, operations,
  mBeanNotificationInfoArray);

}

public Object getAttribute(String attribute_name) {
  if (attribute_name.equals("Name"))
    return name;
  return null;
}

public AttributeList getAttributes(String[] attributeNames) {
  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( (String) attributeNames[i]);
      resultList.add(new Attribute(attributeNames[i], value));
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  return resultList;

}

public void setAttribute(Attribute attribute) {
  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();
  }

}

public AttributeList setAttributes(AttributeList attributes) {
  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;

}


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!");
    return null;
  }else {
    // unrecognized operation name:
    throw new ReflectionException(new NoSuchMethodException(
    operationName),"Cannot find the operation " + operationName + " in " +
      className);
  }

}

public MBeanInfo getMBeanInfo() {
  return mBeanInfo;
}

}

 

 

编制一个HelloAgent来调用这个HelloDynamic:

// java imports
//
import java.util.*;
import java.io.*;
import java.net.*;

// RI imports
//
import javax.management.ObjectName;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;

import com.sun.jdmk.comm.HtmlAdaptorServer;

import javax.management.Attribute;
import com.sun.jmx.trace.Trace;


public class HelloAgent {
public HelloAgent() {
}

public static void main(String[] args) {

  // CREATE the MBeanServer
  //
  System.out.println("\n\tCREATE the MBeanServer.");
  MBeanServer server = MBeanServerFactory.createMBeanServer();

  String domain = server.getDefaultDomain();
  ObjectName object_name = null;
  //使用HelloDynamic 如果为Hello 就是使用我们上章介绍的StandardMbean了
  String mbeanName = "HelloDynamic";
  try {
    
    object_name = new ObjectName(domain + ":type=" + mbeanName);

    server.createMBean(mbeanName,object_name);

    Attribute stateAttribute = new Attribute("Name","I am big one");
    server.setAttribute(object_name,stateAttribute);

    String name = (String) server.getAttribute(object_name,"Name");
    System.out.println("name now is "+name);

    server.invoke(object_name,"print",null,null);
  }
  catch (Exception e) {
    System.out.println("\t!!! Could not create the Hello agent !!!");
    e.printStackTrace();
    return;
  }
}

}

直接运行HelloAgent就可以在屏幕输出上得到
"Hello ,I am big one, this is from HelloDynamic"

JMX架构的了解