前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JMX in action第二篇

JMX in action第二篇

作者头像
Dylan Liu
发布2019-07-01 15:12:26
3740
发布2019-07-01 15:12:26
举报
文章被收录于专栏:dylanliu

一,DynamicMBean

其实一看到Dynamic这个词就基本上确定了,就是反射那一套,不外乎属性获取,设定,方法调用等等,但是这个在使用中是至关重要的,因为现有系统如果都想把接口改造成符合Standard MBean方式的,不太现实,而利用DynamicMBean,通过反射将需要管理的Bean动态生成,对现有系统减少侵入性,也减少了问题产生的可能。来看看DynamicMBean接口

代码语言:javascript
复制
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拥有的属性:

代码语言:javascript
复制
    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类通过反射对类的属性方法获取简化了一下,

代码语言:javascript
复制
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解析出来,比较直观,在我看来是一种更好的办法。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档