一,DynamicMBean
其实一看到Dynamic这个词就基本上确定了,就是反射那一套,不外乎属性获取,设定,方法调用等等,但是这个在使用中是至关重要的,因为现有系统如果都想把接口改造成符合Standard MBean方式的,不太现实,而利用DynamicMBean,通过反射将需要管理的Bean动态生成,对现有系统减少侵入性,也减少了问题产生的可能。来看看DynamicMBean接口
public interface DynamicMBean {
/**
* Obtain the value of a specific attribute of the Dynamic MBean.
*
* @param attribute The name of the attribute to be retrieved
*
* @return The value of the attribute retrieved.
*
* @exception AttributeNotFoundException
* @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's getter.
* @exception ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the getter.
*
* @see #setAttribute
*/
public Object getAttribute(String attribute) throws AttributeNotFoundException,
MBeanException, ReflectionException;
/**
* Set the value of a specific attribute of the Dynamic MBean.
*
* @param attribute The identification of the attribute to
* be set and the value it is to be set to.
*
* @exception AttributeNotFoundException
* @exception InvalidAttributeValueException
* @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's setter.
* @exception ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the MBean's setter.
*
* @see #getAttribute
*/
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException ;
/**
* Get the values of several attributes of the Dynamic MBean.
*
* @param attributes A list of the attributes to be retrieved.
*
* @return The list of attributes retrieved.
*
* @see #setAttributes
*/
public AttributeList getAttributes(String[] attributes);
/**
* Sets the values of several attributes of the Dynamic MBean.
*
* @param attributes A list of attributes: The identification of the
* attributes to be set and the values they are to be set to.
*
* @return The list of attributes that were set, with their new values.
*
* @see #getAttributes
*/
public AttributeList setAttributes(AttributeList attributes);
/**
* Allows an action to be invoked on the Dynamic MBean.
*
* @param actionName The name of the action to be invoked.
* @param params An array containing the parameters to be set when the action is
* invoked.
* @param signature An array containing the signature of the action. The class objects will
* be loaded through the same class loader as the one used for loading the
* MBean on which the action is invoked.
*
* @return The object returned by the action, which represents the result of
* invoking the action on the MBean specified.
*
* @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's invoked method.
* @exception ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the method
*/
public Object invoke(String actionName, Object params[], String signature[])
throws MBeanException, ReflectionException ;
/**
* Provides the exposed attributes and actions of the Dynamic MBean using an MBeanInfo object.
*
* @return An instance of <CODE>MBeanInfo</CODE> allowing all attributes and actions
* exposed by this Dynamic MBean to be retrieved.
*
*/
public MBeanInfo getMBeanInfo();
}
JMX定义几个类是我们需要看的,其一是Attribute,是jmx封装的name-value的类,其二就是MBeanInfo这个了,这个是比较重要的一个类,无论是DynamicMBean还是StandardMBean,在注册到MBean Server中去后,都会统一的处理成MBeanInfo的形式,是的Server可以不用去区分我们的实现而用统一的方式去管理MBean
来看看MBeanInfo拥有的属性:
private transient Descriptor descriptor;
/**
* @serial The human readable description of the class.
*/
private final String description;
/**
* @serial The MBean qualified name.
*/
private final String className;
/**
* @serial The MBean attribute descriptors.
*/
private final MBeanAttributeInfo[] attributes;
/**
* @serial The MBean operation descriptors.
*/
private final MBeanOperationInfo[] operations;
/**
* @serial The MBean constructor descriptors.
*/
private final MBeanConstructorInfo[] constructors;
/**
* @serial The MBean notification descriptors.
*/
private final MBeanNotificationInfo[] notifications;
可以看到,MBeanInfo其实就是对一个类的描述,包含了类名className,属性的集合attributes,操作的集合operations,构造器的集合constructors,还一个是通知集合notifications,这个是jmx中事件相关的属性
DynamicMBean并没有什么神秘的,关键还是使用这个接口的方式,如果对于每一个类都实现这个接口,然后构造一大堆类的元数据,也是挺痛苦的一件事,JIA提供了一个DynamicMBeanSupport类通过反射对类的属性方法获取简化了一下,
public class DynamicMBeanSupport implements DynamicMBean {
List<MBeanAttributeInfo> attributeList = new ArrayList<MBeanAttributeInfo>();
List<MBeanOperationInfo> operationInfos = new ArrayList<MBeanOperationInfo>();
List<MBeanConstructorInfo> constructorInfos = new ArrayList<MBeanConstructorInfo>();
// List<MBeanNotificationInfo> notificationInfos = new ArrayList<MBeanNotificationInfo>();
MBeanInfo mBeanInfo = null;
String description = null;
volatile boolean changedEver = false;
public DynamicMBeanSupport(String description){
this.description = description;
}
/**
* Obtain the value of a specific attribute of the Dynamic MBean.
*
* @param attribute The name of the attribute to be retrieved
* @return The value of the attribute retrieved.
* @throws AttributeNotFoundException
* @throws MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's getter.
* @throws ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the getter.
* @see #setAttribute
*/
@Override
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
//有两种办法,一种获取Field然后反射获得,一种反射getter方法
Class cls=this.getClass();
String getterName = "get"+attribute;//jmx中属性头字母是大写的
try {
Method method = cls.getMethod(getterName,null);
return method.invoke(this,null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* Set the value of a specific attribute of the Dynamic MBean.
*
* @param attribute The identification of the attribute to
* be set and the value it is to be set to.
* @throws AttributeNotFoundException
* @throws InvalidAttributeValueException
* @throws MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's setter.
* @throws ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the MBean's setter.
* @see #getAttribute
*/
@Override
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
//有两种办法,一种获取Field然后反射获得,一种反射setter方法
Class cls=this.getClass();
String attributeName = attribute.getName();
Object attributeValue = attribute.getValue();
attributeName = attributeName.substring(0,1).toLowerCase()+attributeName.substring(1);
try {
Field field = cls.getDeclaredField(attributeName);
field.setAccessible(true);
field.set(this,attributeValue);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* Get the values of several attributes of the Dynamic MBean.
*
* @param attributes A list of the attributes to be retrieved.
* @return The list of attributes retrieved.
* @see #setAttributes
*/
@Override
public AttributeList getAttributes(String[] attributes) {
AttributeList attributeList = new AttributeList();
if(attributes == null || attributes.length == 0){
return null;
}
for(String name : attributes){
try {
attributeList.add(new Attribute(name,this.getAttribute(name)));
} catch (AttributeNotFoundException e) {
e.printStackTrace();
} catch (MBeanException e) {
e.printStackTrace();
} catch (ReflectionException e) {
e.printStackTrace();
}
}
return attributeList;
}
/**
* Sets the values of several attributes of the Dynamic MBean.
*
* @param attributes A list of attributes: The identification of the
* attributes to be set and the values they are to be set to.
* @return The list of attributes that were set, with their new values.
* @see #getAttributes
*/
@Override
public AttributeList setAttributes(AttributeList attributes) {
if(attributes == null || attributes.isEmpty()){
return null;
}
for (Attribute attribute : attributes.asList()){
try {
this.setAttribute(attribute);
} catch (AttributeNotFoundException e) {
e.printStackTrace();
} catch (InvalidAttributeValueException e) {
e.printStackTrace();
} catch (MBeanException e) {
e.printStackTrace();
} catch (ReflectionException e) {
e.printStackTrace();
}
}
return attributes;
}
/**
* Allows an action to be invoked on the Dynamic MBean.
*
* @param actionName The name of the action to be invoked.
* @param params An array containing the parameters to be set when the action is
* invoked.
* @param signature An array containing the signature of the action. The class objects will
* be loaded through the same class loader as the one used for loading the
* MBean on which the action is invoked.
* @return The object returned by the action, which represents the result of
* invoking the action on the MBean specified.
* @throws MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's invoked method.
* @throws ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the method
*/
@Override
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
Class cls = this.getClass();
//signature is the params classes full name,
//I wonder if the params class can also infer the signature
//like blow
// Class[] paramCls = params ==null ? null : new Class[params.length];
// if(paramCls != null){
// for (int i = 0 ; i < params.length ; i++ ){
// paramCls[i] = params[i].getClass();
// }
// }
//just in case , you don't know the inner implementation after all
Class[] paramCls = params ==null ? null : new Class[signature.length];
if(paramCls != null){
for (int i = 0 ; i < signature.length ; i++ ) {
try {
paramCls[i] = Class.forName(signature[i]);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
try {
Method method = cls.getDeclaredMethod(actionName,paramCls);
return method.invoke(this,params);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* Provides the exposed attributes and actions of the Dynamic MBean using an MBeanInfo object.
*
* @return An instance of <CODE>MBeanInfo</CODE> allowing all attributes and actions
* exposed by this Dynamic MBean to be retrieved.
*/
@Override
public MBeanInfo getMBeanInfo() {
synchronized (mBeanInfo){
if(mBeanInfo!=null && !changedEver){
return mBeanInfo;
}
}
buildMBeanInfo(this.description);
return mBeanInfo;
}
/**
* methods for subclass to add attribute
* @param name
* @param description
* @param getter
* @param setter
* @throws IntrospectionException
*/
protected void addAttributeInfo(String name,String description,Method getter,Method setter) throws IntrospectionException {
MBeanAttributeInfo attributeInfo = new MBeanAttributeInfo(name,description,getter,setter);
synchronized (attributeList){
changedEver = true;
attributeList.add(attributeInfo);
}
}
protected void addOperationInfo(String description,Method method){
MBeanOperationInfo operationInfo = new MBeanOperationInfo(description,method);
synchronized (operationInfos){
changedEver = true;
operationInfos.add(operationInfo);
}
}
protected void addConstructorInfo(String description, Constructor constructor){
MBeanConstructorInfo constructorInfo = new MBeanConstructorInfo(description,constructor);
synchronized (constructorInfos){
changedEver = true;
constructorInfos.add(constructorInfo);
}
}
/**
* construct mbeaninfo
* @param description
*/
private void buildMBeanInfo(String description){
synchronized (mBeanInfo){
changedEver = false;
MBeanAttributeInfo [] attributeInfosArray = null;
MBeanOperationInfo [] operationInfosArray = null;
MBeanConstructorInfo[] constructorInfosArray = null;
synchronized (attributeList){
attributeInfosArray = new MBeanAttributeInfo[attributeList.size()];
attributeInfosArray = attributeList.toArray(attributeInfosArray);
}
synchronized (operationInfos){
operationInfosArray = new MBeanOperationInfo[operationInfos.size()];
operationInfosArray = operationInfos.toArray(operationInfosArray);
}
synchronized (constructorInfos) {
constructorInfosArray = new MBeanConstructorInfo[constructorInfos.size()];
constructorInfosArray = constructorInfos.toArray(constructorInfosArray);
}
this.mBeanInfo = new MBeanInfo(this.getClass().getName(),description,attributeInfosArray,
constructorInfosArray,operationInfosArray,null);
}
}
}
其实这种暴露属性方法的方式还是比较粗糙的,因为暴露的方法其实还是硬编码在了子类中
tomcat提供了一种配置方式来暴露,使用一个mb ean-descriptor,将需要暴露的方法属性写到里面,用xml digest解析出来,比较直观,在我看来是一种更好的办法。