关键词搜索

源码搜索 ×
×

从零开始玩转JMX(三)——Model MBean

发布2016-10-14浏览4977次

详情内容


欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


欢迎跳转到本文的原文链接:https://honeypps.com/java/jmx-quick-start-3-model-mbean/

Model MBean

相对于Standard MBean,Model MBean更加灵活。如果我们不能修改已有的Java类,那么使用Model MBean是不错的选择。

Model MBean也是一种专门化的动态管理构件。它是预制的、通用的和动态的 MBean 类,已经包含了所有必要缺省行为的实现,并允许在运行时添加或覆盖需要定制的那些实现。JMX规范规定该类必须实现为javax.management.modelmbean.RequiredModelMBean,管理者要做的就是实例化该类,并配置该构件的默认行为并注册到JMX代理中,即可实现对资源的管理。JMX代理通过获得一个ModelMBeanInfo对象来获取管理接口。
模型管理构件具有以下新的特点:

  • 持久性。定义了持久机制,可以利用Java的序列化或JDBC来存储模型MBean的状态。 就是要保存到硬盘上。
  • 通知和日志功能。能记录每一个发出的通知,并能自动发出属性变化通知。
  • 属性值缓存。具有缓存属性值的能力。

还是沿用前面的代码,但是这里就不需要类似HelloMBean这样的接口了。

package com.test.jmx.modelBean;

public class Hello { //注意这里没有implements任何东西
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void printHello(){
        System.out.println("Hello world, "+name);
    }

    public void printHello(String whoName){
        System.out.println("Hello, "+whoName);
    }
}

    但是需要自己编写一个产生Model MBean的工具类。Model MBean使用JDK提供的RequiredModelMBean,指定基本的Bean(Hello),创建好需要的ModelMBeanInfo就可以了。

    package com.test.jmx.modelBean;
    
    
    import javax.management.*;
    import javax.management.modelmbean.*;
    
    /**
     * Created by hidden on 2016/10/9.
     */
    public class ModelMBeanUtils {
        private static final boolean READABLE = true;
        private static final boolean WRITABLE = true;
        private static final boolean BOOLEAN = true;
        private static final String STRING_CLASS = "java.lang.String";
        public static RequiredModelMBean createModelerMBean() {
            RequiredModelMBean model = null;
            try {
                model = new RequiredModelMBean();
                model.setManagedResource(new Hello(), "ObjectReference");
                ModelMBeanInfo info = createModelMBeanInfo();
                model.setModelMBeanInfo(info);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return model;
        }
        private static ModelMBeanInfo createModelMBeanInfo() {
            //
            //                        属性                                        //
            //
            // 构造name属性信息
            Descriptor portAttrDesc = new DescriptorSupport();
            portAttrDesc.setField("name", "Name");
            portAttrDesc.setField("descriptorType", "attribute");
            portAttrDesc.setField("displayName", "Name");
            portAttrDesc.setField("getMethod", "getName");
            portAttrDesc.setField("setMethod", "setName");
            ModelMBeanAttributeInfo nameAttrInfo = new ModelMBeanAttributeInfo(//
                    "Name", // 属性名
                    STRING_CLASS, //属性类型
                    "people name", // 描述文字
                    READABLE, WRITABLE, !BOOLEAN, // 读写
                    portAttrDesc // 属性描述
            );
            //
            //                        方法                                        //
            //
            // 构造 getName操作描述符信息
            Descriptor getStateDesc = new DescriptorSupport(new String[] {
                    "name=getName",
                    "descriptorType=operation",
                    "class=com.test.jmx.modelBean.Hello",
                    "role=operation"
            });
    
            ModelMBeanOperationInfo getName = new ModelMBeanOperationInfo(//
                    "getName", //
                    "get name attribute", //
                    null, //
                    "java.lang.String", //
                    MBeanOperationInfo.ACTION, //
                    getStateDesc //
            );
    
            // 构造 setName操作描述符信息
            Descriptor setStateDesc = new DescriptorSupport(new String[] {
                    "name=setName", "descriptorType=operation", "class=com.test.jmx.modelBean.Hello",
                    "role=operation" });
    
            MBeanParameterInfo[] setStateParms = new MBeanParameterInfo[] { (new MBeanParameterInfo(
                    "name", "java.lang.String", "new name value")) };
    
            ModelMBeanOperationInfo setName = new ModelMBeanOperationInfo(//
                    "setName", //
                    "set name attribute", //
                    setStateParms, //
                    "void", //
                    MBeanOperationInfo.ACTION, //
                    setStateDesc //
            );
    
            //构造 printHello()操作的信息
            ModelMBeanOperationInfo print1Info = new ModelMBeanOperationInfo(//
                    "printHello", //
                    null, //
                    null, //
                    "void", //
                    MBeanOperationInfo.INFO, //
                    null //
            );
            // 构造printHello(String whoName)操作信息
            ModelMBeanOperationInfo print2Info;
            MBeanParameterInfo[] param2 = new MBeanParameterInfo[1];
            param2[0] = new MBeanParameterInfo("whoName", STRING_CLASS, "say hello to who");
            print2Info = new ModelMBeanOperationInfo(//
                    "printHello", //
                    null,//
                    param2,//
                    "void", //
                    MBeanOperationInfo.INFO, //
                    null//
            );
            //
            //                        最后总合                                    //
            //
            // create ModelMBeanInfo
            ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(//
                    RequiredModelMBean.class.getName(), // MBean类
                    null, // 描述文字
                    new ModelMBeanAttributeInfo[] { // 所有的属性信息(数组)
                            nameAttrInfo },//只有一个属性
                    null, // 所有的构造函数信息
                    new ModelMBeanOperationInfo[] { // 所有的操作信息(数组)
                            getName,
                            setName,
                            print1Info,
                            print2Info },//
                    null, // 所有的通知信息(本例无)
                    null//MBean描述
            );
            return mbeanInfo;
        }
    }
    
      22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123

    这里着重说明下ModelMBeanInfo接口
    编写Model MBean的最大挑战是告诉Model MBean对象托管资源的那些熟悉和方法可以暴露给代理。ModelMBeanInfo对象描述了将会暴露给代理的构造函数、属性、操作甚至是监听器。
    创建了ModelMBeanInfo对象后,需要将其与ModelMBean对象关联。目前有两种方式可以做到这一点:

    • 传入ModelMBeanInfo对象给RequiredModelMBean对象的构造函数。
    • 调用RequiredModelMBean对象的setModelMBeanInfo方法。

    创建了ModelMBean对象后(RequiredModelMBean implements ModelMBean),需要调用ModelMBean接口的setManagedResource()方法将其与托管资源关联,该方法如下:

    public void setManagedResource(Object managedResource, String managedResourceType) ;
    
    • 1

    managedResourceType的值可以为ObjectReference, Handle, IOR, EJBHandle或RMIReference,但当前只支持ObjectReference.

    在注册时没有什么特别之处,只是需要注意下通过工具类获得MBean即可

    package com.test.jmx.modelBean;
    
    import com.sun.jdmk.comm.HtmlAdaptorServer;
    
    import javax.management.*;
    import javax.management.modelmbean.RequiredModelMBean;
    import java.lang.management.ManagementFactory;
    
    public class HelloAgent {
        public static void main(String[] args) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
    
            ObjectName helloName = new ObjectName("MyMBean:name=HelloWorld");
            //Hello hello = new Hello();
            RequiredModelMBean hello = ModelMBeanUtils.createModelerMBean();
            server.registerMBean(hello, helloName);
    
            ObjectName adapterName = new ObjectName("MyMBean:name=htmladapter,port=8082");
            HtmlAdaptorServer adapter = new HtmlAdaptorServer();
            server.registerMBean(adapter, adapterName);
            adapter.start();
        }
    }
    
      22
    • 23

    运行结果:略。

    Model MBean可以动态配置。试想一下这个应用场景:由于安全或其他原因,系统要把某个MBean公开的可管理方法隐藏起来。这时,如果你是用标准MBean,这需要修改接口类,然后重新编译发布;如果用 Apache commons-modeler(如果不想总要维护MBean这个借口,那么可以使用Apache的commons-modeler来辅助开发MBean,所有的MBean都装配在XML文件中)来写的模型MBean,则只需要修改XML文件就行了,不需要重新编译发布(可能要重启一下系统)。这就是Model Mbean 优势之所在了。


    参考资料

    1. JMX整理
    2. JMX简介
    3. http://blog.csdn.net/DryKillLogic/article/category/762777
    4. 用Apache的commons-modeler来辅助开发JMX

    欢迎跳转到本文的原文链接:https://honeypps.com/java/jmx-quick-start-3-model-mbean/


    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载