一、什么是JMX
JMX是Java Management Extension的缩写,是Java SE平台的一部分;JMX框架的目的是用来管理我们的Application,设备(比如网络,内存,缓存等)等可以用我们的Java类描述控制的一切“资源”。JMX定义一系列规范(包括命名规范、远程调用协议)、API等,JMX通过Managed Beans(MBeans)来管理制定资源,而这些MBeans都需要注册到一个core-managed object server(MBeans Server) ,该Server可以看成资源管理客户端(或代理),只要可以运行JVM的地方,就可以运行这个代理。
二、JMX框架结构
如下图,应用程序将需要管理的资源类实现MBean的接口(即通过MBean来装配该类),MBean注册到MBeans Server代理;代理通过JMX connector将MBeans接口暴露给客户端(资源监控管理端),客户端就可以通过MBeans接口来实现对Application中的资源进行查询、修改等管理了。其中JMX Connector未指定协议,可以RMI、STMP等协议都可以,只要实现connector接口。
三、实现样例
以Oracle提供JMX样例进行讲解
1)首先定义资源管理类MBean Interface:这个接口定义MBean怎么管理类或资源;按JMX的命名规范,MBean接口必须以MBean结尾。
/*
* HelloMBean.java - MBean interface describing the management operations and
* attributes for the Hello World MBean. In this case there are two operations,
* "sayHello" and "add", and two attributes, "Name" and "CacheSize".
*/
package com.example;
public interface HelloMBean {
//-----------
// operations
//-----------
public void sayHello();
public int add(int x, int y);
//-----------
// attributes
//-----------
// a read-only attribute called Name of type String
public String getName();
// a read-write attribute called CacheSize of type int
public int getCacheSize();
public void setCacheSize(int size);
}
2)实现MBean 接口。将需要管理的资源,通过接口实现管理。所以在实际开发过程中,可能会先有资源类,后续如果需要对其属性进行管理,再添加MBean接口类和实现方法。
/*
* Hello.java - MBean implementation for the Hello MBean. This class must
* implement all the Java methods declared in the HelloMBean interface,
* with the appropriate behavior for each one.
*/
package com.example;
import javax.management.*;
public class Hello implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}
public int add(int x, int y) {
return x + y;
}
/*
* Getter for the Name attribute. The pattern shown here is frequent: the
* getter returns a private field representing the attribute value. In our
* case, the attribute value never changes, but for other attributes it
* might change as the application runs. Consider an attribute representing
* statistics such as uptime or memory usage, for example. Being read-only
* just means that it can't be changed through the management interface.
*/
public String getName() {
return this.name;
}
/*
* Getter for the CacheSize attribute. The pattern shown here is frequent:
* the getter returns a private field representing the attribute value, and
* the setter changes that field.
*/
public int getCacheSize() {
return this.cacheSize;
}
/*
* Setter for the CacheSize attribute. To avoid problems with stale values
* in multithreaded situations, it is a good idea for setters to be
* synchronized.
*/
public synchronized void setCacheSize(int size) {
int oldSize = this.cacheSize;
this.cacheSize = size;
/*
* In a real application, changing the attribute would typically have
* effects beyond just modifying the cacheSize field. For example,
* resizing the cache might mean discarding entries or allocating new
* ones. The logic for these effects would be here.
*/
System.out.println("Cache size now " + this.cacheSize);
}
private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
private long sequenceNumber = 1;
}
3)创建MBeans的代理,并将实现的MBean注册到代理,以便远程客户端可以访问。
/*
* Main.java - main class for the Hello MBean and QueueSampler MXBean example.
* Create the Hello MBean and QueueSampler MXBean, register them in the platform
* MBean server, then wait forever (or until the program is interrupted).
*/
package com.example;
import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class Main {
/*
* For simplicity, we declare "throws Exception". Real programs will usually
* want finer-grained exception handling.
*/
public static void main(String[] args) throws Exception {
// Get the Platform MBean Server
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// Construct the ObjectName for the Hello MBean we will register
ObjectName mbeanName = new ObjectName("com.example:type=Hello");
// Create the Hello World MBean
Hello mbean = new Hello();
// Register the Hello World MBean
mbs.registerMBean(mbean, mbeanName);
// Wait forever
System.out.println("Waiting for incoming requests...");
Thread.sleep(Long.MAX_VALUE);
}
}
4)启动本地服务,执行com.example.Main.main()方法,进行验证。其中客户端,可以启用Oracle JDK带的Jconsole连接本地的代理。