目录
目录
JMX是什么
JMX(Java Management Extensions)是一个为应用程序植入管理功能的标准化代理和服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等。JConsole以及JVisualVM 都是通过JMX来实现对JAVA应用程序的监控。
JMX架构
MBean
JMX定义了四种类型的MBean,标准MBean,动态MBean,开放MBean和模型MBean
- 标准MBean是最简单的实现,他们的管理接口是通过方法名描述的。MXBean是是一种标准的MBean,它使用开放的MBean概念,在简化代码的同事,达到易于管理的目的。
- 动态MBean必须实现特定的接口,但是他们在运行时对外提供管理接口,所以具有很大的灵活性。
- 开放MBean是动态MBean
- 模型MBean也是动态MBean,它是运行时完全可配置和自我描述的。它们为动态设备层资源提供具有默认行为的一般MBean类。
任何一个作为MBean的java实现的java对象,被注册到代理上后,都可以从代理机构的JVM外管理。因此,应用程序中使用JMX只需要两步:
- 编写MBean提供管理接口和监控数据
- 将MBean注册到MBeanServer
下面本别就四种MBean去看看如何使用
标准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;
}
}
注册MBean
/**
*
*
* @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);
}
}
使用MBean
运行后的可以通过jconsole看到MBean

此时可以发现无法通过Web去管理MBean,那么如何通过Web去管理呢?
如何通过Web管理MBean
要想通过Web去管理MBean需要创建一个HtmlAdapterServer,并将其注册到MBeanServer
具体代码示例如下:
/**
* 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视图页面

开放类型MBean
开放类型MBean与标准MBean的区别在于接口中引用到一些其他类型的类时的表象方式不同。在MXBean中,如果MXBean的结偶定义了一个自定义属性,当JMX使用这个MXBean时这个类型会被转换成一种标准的类型(CompositeDataSupport),这些类型称之为开发类型。具体代码如下:
自定义参数
/**
*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接口定义
/**
*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接口实现
/**
*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();
}
}
}
MXBean注册
/**
* 测试方法
* @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);
}
}
访问MXBean

动态MBean
动态MBean是运行期才定义它的属性和方法,也就是说它有什么属性和方法都是可以动态改变的。动态MBean是利用一些辅助类(MBeanConstructorInfo,MBeanAtrributeInfo,MBeanOperationInfo)来完成这些功能的。具体代码示例如下:
/**
* 动态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
上文中都是介绍使用Jconsole调用MBean,有没有客户端可以直接调用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 %
本文详细介绍了Java Management Extensions (JMX)的概念、架构,并深入讲解了标准MBean、开放类型MBean(MXBean)以及动态MBean的使用,包括定义接口、实现、注册和调用。此外,还探讨了如何通过Web管理MBean以及客户端调用MBean的方法。

被折叠的 条评论
为什么被折叠?



