JMX 基础Demo

        JMX在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等

优点可以非常容易的使应用程序具有被管理
伸缩性的架构每个JMX Agent服务可以很容易的放入到Agent中,每个JMX的实现都提供几个核心的Agent服务,你也可以自己编写服务,服务可以很容易的部署,取消部署。
 
  • MBean方式

   一个MBean 是一个遵循特定设计模式的和实现了特定接口的Java对象。MBean管理接口有如下描述:

  1. 可访问的属性值
  2. 可调用的操作
  3. 可以发送的消息
  4. MBean java的构造器

任何一个作为MBean的java实现的java对象,被注册到代理上后,都可以从代理机构的JVM外管理。

JMX定义了四周类型的MBean,标准MBean,动态MBean,开放MBean和模型MBean

  1. 标准MBean是最简单的实现,他们的管理接口是通过方法名描述的。MXBean是是一种标准的MBean,它使用开放的MBean概念,在简化代码的同事,达到易于管理的目的。
  2. 动态MBean必须实现特定的接口,但是他们在运行时对外提供管理接口,所以具有很大的灵活性。
  3. 开放MBean是动态MBean
  4. 模型MBean也是动态MBean,它是运行时完全可配置和自我描述的。它们为动态设备层资源提供具有默认行为的一般MBean类。

这些对

主要提供接口,允许有不同的实现
/**
 *定义一个普通的接口
 *
 * @author zhangwei_david
 * @version $Id: HiMBean.java, v 0.1 2015年1月24日 下午1:16:15 zhangwei_david Exp $
 */
public interface HiMBean {
    /**
     *打招呼
     */
    public void sayHello();

    /**
     * 加法计算器
     *
     * @param x
     * @param y
     * @return
     */
    public int add(int x, int y);

    /**
     * 获取名称
     *
     * @return
     */
    public String getName();

    /**
     *获取缓存大小
     *
     * @return
     */
    public int getCacheSize();

    /**
     *设置缓存大小
     *
     * @param size
     */
    public void setCacheSize(int size);
}
/**
 *简单实现类
 * @author Lenovo
 * @version $Id: Hi.java, v 0.1 2014年9月26日 下午2:48:09 Lenovo Exp $
 */
public class HiMbeanImpl implements HiMBean {

    private final String     name               = "Reginald";
    private int              cacheSize          = DEFAULT_CACHE_SIZE;
    private static final int DEFAULT_CACHE_SIZE = 200;

    /**
     * @see com.cathy.demo.jmx.notifications.HiMBean#sayHello()
     */
    public void sayHello() {
        System.out.println("Hello," + getName());
    }

    /**
     * @see com.cathy.demo.jmx.notifications.HiMBean#add(int, int)
     */
    public int add(int x, int y) {
        return x + y;
    }

    /**
     * @see com.cathy.demo.jmx.notifications.HiMBean#getName()
     */
    public String getName() {
        return name;
    }

    /**
     * @see com.cathy.demo.jmx.notifications.HiMBean#getCacheSize()
     */
    public int getCacheSize() {
        return cacheSize;
    }

    /**
     * @see com.cathy.demo.jmx.notifications.HiMBean#setCacheSize(int)
     */
    public void setCacheSize(int size) {
        cacheSize = size;
    }

}

使用 Model MBean 的过程也是下面几步:

  1. 创建一个 MBServer:mBeanServe
  2. 获得管理资源用的 MBean:serverBean
  3. 给这个 MBean 一个 ObjectName:serverMBeanName
  4. 将 serverBean 以 serverMBeanName 注册到 mBeanServer 上去
/**
 * 
 * 
 * @author zhangwei_david
 * @version $Id: Main.java, v 0.1 2015年6月19日 下午1:10:03 zhangwei_david Exp $
 */
public class Main {

    /**
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //获取Mean的平台服务
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        // 对即将被注册的MBean 构造一个ObjectName
        ObjectName objectName = new ObjectName("com.cathy.demo.jmx:type=Hi");
        // 创建一个Mbean
        RequiredModelMBean mbean = new RequiredModelMBean();
        HiMbeanImpl hiMbean = new HiMbeanImpl();
        mbean.setManagedResource(hiMbean, "objectReference");

        ModelMBeanAttributeInfo name = new ModelMBeanAttributeInfo("name", "java.lang.String",
            "userName", true, true, false, new DescriptorSupport(new String[] { "name=name",
                    "descriptorType=attribute", "getMethod=getName", "setMethod=setName" }));

        ModelMBeanOperationInfo sayHello = new ModelMBeanOperationInfo("say Hello", hiMbean
            .getClass().getMethod("sayHello"));
        // 创建一个ModelMBeanOperationInfo
        ModelMBeanOperationInfo getName = new ModelMBeanOperationInfo("get userName", hiMbean
            .getClass().getMethod("getName"));

        // 使用ModelMbeanAttributeInfo和ModelMbeanOperationInfo构建一个ModelMBeanInfo对象
        ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport("HiMbean", "Test",
            new ModelMBeanAttributeInfo[] { name }, null, new ModelMBeanOperationInfo[] { sayHello,
                    getName }, null);
        // 向ModelMBean 设置ModelMBeanInfo
        mbean.setModelMBeanInfo(mbeanInfo);

        // 将Mbean 注册到MBeanServer
        mbs.registerMBean(mbean, objectName);
        // 一直等待
        System.out.println("Waiting forever...");
        Thread.sleep(Long.MAX_VALUE);

    }
}

运行后的可以通过jconsole看到MBean



 

通过HTML页面管理MBean

/**
 * Alipay.com Inc.
 * Copyright (c) 2004-2014 All Rights Reserved.
 */
package com.cathy.demo.jmx;

import java.lang.management.ManagementFactory;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.modelmbean.RequiredModelMBean;

import com.sun.jdmk.comm.HtmlAdaptorServer;

/**
 *
 *
 * @author zhangwei_david
 * @version $Id: Main.java, v 0.1 2015年6月19日 下午1:10:03 zhangwei_david Exp $
 */
public class Main {

    /**
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //获取Mean的平台服务
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        // 对即将被注册的MBean 构造一个ObjectName
        ObjectName objectName = new ObjectName("com.cathy.demo.jmx:type=Hi");
        // 创建一个Mbean
        RequiredModelMBean mbean = new RequiredModelMBean();
        HiMbeanImpl hiMbean = new HiMbeanImpl();
        mbean.setManagedResource(hiMbean, "objectReference");

        ModelMBeanAttributeInfo name = new ModelMBeanAttributeInfo("name", "java.lang.String",
            "userName", true, true, false, new DescriptorSupport(new String[] { "name=name",
                    "descriptorType=attribute", "getMethod=getName", "setMethod=setName" }));

        ModelMBeanOperationInfo sayHello = new ModelMBeanOperationInfo("say Hello", hiMbean
            .getClass().getMethod("sayHello"));
        // 创建一个ModelMBeanOperationInfo
        ModelMBeanOperationInfo getName = new ModelMBeanOperationInfo("get userName", hiMbean
            .getClass().getMethod("getName"));

        // 使用ModelMbeanAttributeInfo和ModelMbeanOperationInfo构建一个ModelMBeanInfo对象
        ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport("HiMbean", "Test",
            new ModelMBeanAttributeInfo[] { name }, null, new ModelMBeanOperationInfo[] { sayHello,
                    getName }, null);
        // 向ModelMBean 设置ModelMBeanInfo
        mbean.setModelMBeanInfo(mbeanInfo);

        // 将Mbean 注册到MBeanServer
        mbs.registerMBean(mbean, objectName);

        // 创建一个HtmlAdapterServer MBean
        HtmlAdaptorServer htmlAdaptorServer = new HtmlAdaptorServer();
        // 修改端口号
        htmlAdaptorServer.setPort(8082);
        // 将html适配器MBean 注入到MBeanServer,该处port仅仅是描述
        mbs.registerMBean(htmlAdaptorServer, new ObjectName("Adaptor:name=html,port=8082"));
        // 启动适配器
        htmlAdaptorServer.start();
        // 一直等待
        System.out.println("Waiting forever...");
        Thread.sleep(Long.MAX_VALUE);

    }
}

可以通过 http://localhost:8082/ 访问



 

点击【type=Hi】进入MBean视图页面



 

  •  MXBean
/**
 *MXBean参数对象
 * @author zhangwei_david
 * @version $Id: QueueSample.java, v 0.1 2015年6月20日 下午4:30:30 zhangwei_david Exp $
 */
public class QueueSample {

    private final Date   date;
    private final int    size;
    private final String head;

    @ConstructorProperties({ "date", "size", "head" })
    public QueueSample(Date date, int size, String head) {
        this.date = date;
        this.size = size;
        this.head = head;
    }

    public Date getDate() {
        return date;
    }

    public int getSize() {
        return size;
    }

    public String getHead() {
        return head;
    }
}
/**
 *MXBean接口,定义两个操作
 *
 * @author zhangwei_david
 * @version $Id: QueueSamplerMXBean.java, v 0.1 2015年6月20日 下午4:31:34 zhangwei_david Exp $
 */
public interface QueueSamplerMXBean {

    public QueueSample getQueueSample();

    public void clearQueue();
}
/**
 *MXBean的实现类
 * @author zhangwei_david
 * @version $Id: QueueSampler.java, v 0.1 2015年6月20日 下午4:32:19 zhangwei_david Exp $
 */
public class QueueSampler implements QueueSamplerMXBean {

    private Queue<String> queue;

    public QueueSampler(Queue<String> queue) {
        this.queue = queue;
    }

    public QueueSample getQueueSample() {
        synchronized (queue) {
            return new QueueSample(new Date(), queue.size(), queue.peek());
        }
    }

    public void clearQueue() {
        synchronized (queue) {
            queue.clear();
        }
    }

}
/**
 * 测试方法
 * @author zhangwei_david
 * @version $Id: TestMain.java, v 0.1 2015年6月20日 下午4:33:35 zhangwei_david Exp $
 */
public class TestMain {
    public static void main(String[] args) throws Exception {
        //获取MBeanServer
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        //构造一个ObjectName
        ObjectName mxbeanName = new ObjectName("com.example:type=QueueSampler");

        // 创建一个队列
        Queue<String> queue = new ArrayBlockingQueue<String>(10);
        queue.add("Request-1");
        queue.add("Request-2");
        queue.add("Request-3");
        // 构造一个mxbean
        QueueSampler mxbean = new QueueSampler(queue);

        // 注册mxbean
        mbs.registerMBean(mxbean, mxbeanName);

        //等待
        System.out.println("Waiting for incoming requests...");
        Thread.sleep(Long.MAX_VALUE);
    }
}

 

  •  动态MBean

/**
 * 动态MBean 示例
 * 
 * @author zhangwei_david
 * @version $Id: HelloDynamic.java, v 0.1 2015年6月21日 下午10:53:07 zhangwei_david Exp $
 */
public class HelloDynamic implements DynamicMBean {

    // 管理控件(MBean)属性
    private String                  name;

    // 动态创建MBean需要的变量
    private String                  className   = this.getClass().getName();
    // 描述
    private String                  description = "Simple implementation of a dynamic MBean.";
    //管理资源
    private MBeanAttributeInfo[]    attributes;
    // 构造方法
    private MBeanConstructorInfo[]  constructors;
    // 操作
    private MBeanOperationInfo[]    operations;

    private MBeanInfo               mBeanInfo;
    // 通知
    private MBeanNotificationInfo[] notifications;

    /**
     * 构造方法
     */
    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];
        notifications = new MBeanNotificationInfo[0];
    }

    private void buildDynamicMBean() {
        // 构造方法
        Constructor<?>[] ctors = this.getClass().getConstructors();
        constructors[0] = new MBeanConstructorInfo(
            "HelloDynamic(): Constructs a HelloDynamic object", ctors[0]);
        // 属性
        attributes[0] = new MBeanAttributeInfo("name", "java.lang.String", "Name: name string",
            true, true, false);
        // 方法
        MBeanParameterInfo[] params = null;
        operations[0] = new MBeanOperationInfo("print", "print(): print the name", params, "void",
            MBeanOperationInfo.INFO);
        // MBeanInfo
        mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations,
            notifications);
    }

    /**
     *
     * @see javax.management.DynamicMBean#getAttribute(java.lang.String)
     */
    public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException,
                                                ReflectionException {
        LoggerUtils.info("获取属性:" + attribute);
        if (attribute == null) {
            return null;
        }
        if ("name".equals(attribute)) {
            return name;
        }
        return null;
    }

    public AttributeList getAttributes(String[] attributes) {
        LoggerUtils.info("获取属性列表" + attributes);
        if (attributes == null) {
            return null;
        }
        AttributeList reslist = new AttributeList();

        for (String attr : attributes) {
            try {
                Object value = getAttribute(attr);
                reslist.add(new Attribute(attr, value));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return reslist;
    }

    /**
     *
     * @see javax.management.DynamicMBean#getMBeanInfo()
     */
    public MBeanInfo getMBeanInfo() {
        return mBeanInfo;
    }

    /**
     *
     * @see javax.management.DynamicMBean#invoke(java.lang.String, java.lang.Object[], java.lang.String[])
     */
    public Object invoke(String actionName, Object[] params, String[] signature)
                                                                                throws MBeanException,
                                                                                ReflectionException {
        LoggerUtils.info(MessageFormat.format("反射调用方法 {0},参数: {1}>签名 {2}", actionName, params,
            signature));
        if (actionName.equals("print")) {
            print();
        } else if ("dynamicPrint".equals(actionName)) {
            dynamicPrint();
        }
        return null;
    }

    /**
     *
     * @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute)
     */
    public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
                                                 InvalidAttributeValueException, MBeanException,
                                                 ReflectionException {
        if (attribute == null) {
            return;
        }

        String attrname = attribute.getName();
        Object attrvalue = attribute.getValue();

        if ("name".equals(attrname)) {
            if (attrvalue == null) {
                name = null;
            } else {
                try {
                    if (Class.forName("java.lang.String").isAssignableFrom(attrvalue.getClass())) {
                        name = (String) attrvalue;
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     *
     * @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList)
     */
    public AttributeList setAttributes(AttributeList attributes) {
        if (attributes == null) {
            return null;
        }
        AttributeList reslist = new AttributeList();
        for (Object obj : attributes) {
            Attribute attr = (Attribute) obj;
            try {
                setAttribute(attr);
                String attrname = attr.getName();
                Object attrvalue = attr.getValue();
                reslist.add(new Attribute(attrname, attrvalue));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return reslist;
    }

    private void print() {
        System.out.println(MessageFormat.format("Hello {0}, This is helloDynamic", name));
        // add method dynamic at runtime
        operations = new MBeanOperationInfo[2];
        buildDynamicMBean();
        MBeanParameterInfo[] parameters = null;
        operations[1] = new MBeanOperationInfo("dynamicPrint",
            "dynamicPrint: Runtime generated by print method", parameters, "void",
            MBeanOperationInfo.INFO);
    }

    private void dynamicPrint() {
        System.out.println("This is a runtime generated method!");
    }

}
/**
 * 
 * 
 * @author zhangwei_david
 * @version $Id: HelloDynamicAgent.java, v 0.1 2015年6月21日 下午10:53:51 zhangwei_david Exp $
 */
public class HelloDynamicAgent {
    private static String DOMAIN = "MyDynamicMBean";

    /**
     * @param args
     * @throws NullPointerException
     * @throws MalformedObjectNameException
     * @throws NotCompliantMBeanException
     * @throws MBeanRegistrationException
     * @throws InstanceAlreadyExistsException
     */
    public static void main(String[] args) throws MalformedObjectNameException,
                                          NullPointerException, InstanceAlreadyExistsException,
                                          MBeanRegistrationException, NotCompliantMBeanException {
        //创建一个MBean服务对象,DOMAIN类似于java里面的公共package部分
        MBeanServer server = MBeanServerFactory.createMBeanServer(DOMAIN);
        //创建DynamicMBean对象
        HelloDynamic hello = new HelloDynamic();
        //创建一个web适配器服务器,表示我们MBean服务通过web形式来提供给用户管理
        HtmlAdaptorServer htmlserver = new HtmlAdaptorServer();
        htmlserver.setPort(9999);
        //ObjctName对象类似于完整的package
        ObjectName helloname = new ObjectName(DOMAIN + ":name=HelloDynamic");
        ObjectName htmlname = new ObjectName(DOMAIN + ":name=HtmlAdaptor");
        server.registerMBean(hello, helloname);
        server.registerMBean(htmlserver, htmlname);

        htmlserver.start();
    }

}
2015-06-21 22:51:17,854 DEBUG LoggerContext[name=sun.misc.Launcher$AppClassLoader@1d16e93, org.apache.logging.log4j.core.LoggerContext@1e7e365] started OK.
2015-06-21 22:51:17,856 DEBUG Using default SystemClock for timestamps
22:51:17.863 [Thread-1] INFO  com.cathy.demo.util.LoggerUtils - 获取属性:name
22:51:21.698 [Thread-1] INFO  com.cathy.demo.util.LoggerUtils - 反射调用方法 print,参数: [Ljava.lang.Object;@107c4b5>签名 [Ljava.lang.String;@a46b89
Hello David, This is helloDynamic

上述是发布一个Mbean,下面简单介绍一个远程调用一个MBean

/**
 * Alipay.com Inc.
 * Copyright (c) 2004-2015 All Rights Reserved.
 */
package com.cathy.demo.jmx.notifications;

import java.lang.management.MemoryUsage;
import java.text.MessageFormat;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

/**
 *
 * @author zhangwei_david
 * @version $Id: ClientTest.java, v 0.1 2015年6月20日 下午4:52:49 zhangwei_david Exp $
 */
public class ClientTest {

    private static final long   KB_SIZE     = 1024;

    private static final String LOG_PATTERN = "{0}: 分配 {1} KB;  最大值 {2} KB; 已使用 {3} KB;  使用率 {4} %";

    /**
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        JMXServiceURL serviceURL = new JMXServiceURL(
                "service:jmx:rmi://localhost/jndi/rmi://localhost:9999/jmxrmi");
        JMXConnector jmxc = JMXConnectorFactory.connect(serviceURL);
        MBeanServerConnection msc = jmxc.getMBeanServerConnection();
        // 获取所有的ObjectName
        Set<ObjectName> objectNames = msc.queryNames(null, null);
        for (ObjectName objectName : objectNames) {
            System.out.println("ObjectName:" + objectName.getCanonicalName() + ".");
        }

        ObjectName name = new ObjectName("java.lang:type=OperatingSystem");
        System.out.println(msc.getAttributes(name, new String[] { "CommittedVirtualMemorySize",
                                                                  "FreePhysicalMemorySize", "FreeSwapSpaceSize" }));

        printLog(msc, "java.lang:name=Metaspace,type=MemoryPool",
            "java.lang:name=Survivor Space,type=MemoryPool",
            "java.lang:name=Eden Space,type=MemoryPool",
            "java.lang:name=Code Cache,type=MemoryPool",
                "java.lang:name=Tenured Gen,type=MemoryPool");
    }

    private static void printLog(MBeanServerConnection msc, String... name) throws Exception {
        for (String string : name) {
            log(string, getUsageByName(msc, string));
        }
    }

    private static MemoryUsage getUsageByName(MBeanServerConnection msc, String name)
            throws Exception {
        return MemoryUsage.from((CompositeDataSupport) msc.getAttribute(new ObjectName(name),
            "Usage"));
    }

    private static void log(String key, MemoryUsage usage) {
        System.out.println();
        System.out.println(MessageFormat.format(LOG_PATTERN, key, usage.getCommitted() / KB_SIZE,
            usage.getMax() / KB_SIZE, usage.getUsed() / KB_SIZE,
            usage.getUsed() * 100 / usage.getCommitted()));
    }
}

 运行的结果是:

ObjectName:java.lang:name=Metaspace,type=MemoryPool.
ObjectName:java.lang:name=Eden Space,type=MemoryPool.
ObjectName:java.lang:name=Survivor Space,type=MemoryPool.
ObjectName:java.lang:name=Copy,type=GarbageCollector.
ObjectName:JMImplementation:type=MBeanServerDelegate.
ObjectName:java.lang:type=Runtime.
ObjectName:java.lang:type=Threading.
ObjectName:java.lang:type=OperatingSystem.
ObjectName:java.lang:name=MarkSweepCompact,type=GarbageCollector.
ObjectName:java.lang:name=Code Cache,type=MemoryPool.
ObjectName:java.nio:name=direct,type=BufferPool.
ObjectName:java.lang:type=Compilation.
ObjectName:java.lang:name=Tenured Gen,type=MemoryPool.
ObjectName:java.lang:name=CodeCacheManager,type=MemoryManager.
ObjectName:java.lang:type=Memory.
ObjectName:java.nio:name=mapped,type=BufferPool.
ObjectName:java.util.logging:type=Logging.
ObjectName:java.lang:type=ClassLoading.
ObjectName:java.lang:name=Metaspace Manager,type=MemoryManager.
ObjectName:com.sun.management:type=DiagnosticCommand.
ObjectName:com.sun.management:type=HotSpotDiagnostic.
[CommittedVirtualMemorySize = 33554432, FreePhysicalMemorySize = 3817508864, FreeSwapSpaceSize = 9955905536]

java.lang:name=Metaspace,type=MemoryPool: 分配 5,120 KB;  最大值 0 KB; 已使用 5,025 KB;  使用率 98 %

java.lang:name=Survivor Space,type=MemoryPool: 分配 512 KB;  最大值 8,704 KB; 已使用 0 KB;  使用率 0 %

java.lang:name=Eden Space,type=MemoryPool: 分配 4,480 KB;  最大值 69,952 KB; 已使用 1,244 KB;  使用率 27 %

java.lang:name=Code Cache,type=MemoryPool: 分配 992 KB;  最大值 32,768 KB; 已使用 961 KB;  使用率 96 %

java.lang:name=Tenured Gen,type=MemoryPool: 分配 10,944 KB;  最大值 174,784 KB; 已使用 1,915 KB;  使用率 17 %
原文地址:https://www.cnblogs.com/wei-zw/p/8797767.html