JMX【Java Management Extensions】 java管理扩展。简而言之,它提供一个统一的接口来管理一些系统资源。例如,你可能需要在某一时刻手动的删除服务器内存中的数据。那可行的解决方案就是提供一个页面,然后用户可在这个页面是做各种操作,然后发各种请求给服务器,然后服务器相应用户请求,做相应操作。而利用jmx就不需要自己去创建页面,只需将所要提供的服务注册到jmx,利用原生的jconsole就能控制系统资源。
一 注册MBean并通过JConsole查看MBean
1.HelloMBean.java
package mbean;
public interface HelloMBean {
public void sayHello();
public void setName(String name);
public String getName();
}
2.Hello.java
package mbean;
public class Hello implements HelloMBean {
private String name;
@Override
public void sayHello() {
System.out.println("say hello...");
}
@Override
public void setName(String name) {
this.name=name;
}
@Override
public String getName() {
return name;
}
}
3.Main.java[注册MBean]
package mbean;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class Main {
public static void main(String[] args) throws Exception{
System.out.println(System.getProperties());
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=Hello");
Hello mbean = new Hello();
mbs.registerMBean(mbean, name);
System.out.println("Waiting forever...");
Thread.sleep(Long.MAX_VALUE);
}
}
编写MBean接口时,命名必须以MBean结尾,并且相应的实现类【这里是Hello.java】必须和接口【这里是HelloMBean.java】在同一包下。
4. 通过JConsole查看注册的MBean。
二 注册MXBean并通过JConsole查看
1.QueueSample.java
package mxbean;
import java.util.Date;
public class QueueSample {
private final Date date;
private final int size;
private final String 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;
}
}
2.QueueSamplerMXBean.java
package mxbean;
public interface QueueSamplerMXBean {
public QueueSample getQueueSample();
public void clearQueue();
}
3.QueueSampler.java
package mxbean.impl;
import java.util.Date;
import java.util.Queue;
import mxbean.QueueSample;
import mxbean.QueueSamplerMXBean;
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接口时,没有像MBean那么多约束。接口命名可以以MXBean结尾也可以不用,只需要在接口上添加@MXBean注解来表明这个是一个MXBean。而且实现了可以与接口在不同包。最重要的是MXBean可以定义复杂的数据类型。
4 .Main.java[注册MXBean]
package mxbean;
import java.lang.management.ManagementFactory;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import mxbean.impl.QueueSampler;
public class Main {
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
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");
QueueSampler mxbean = new QueueSampler(queue);
mbs.registerMBean(mxbean, mxbeanName);
System.out.println("Waiting...");
Thread.sleep(Long.MAX_VALUE);
}
}
5. 通过JConsole查看
三 使用JMX Notification
1.AnimalMBean.java
package notification;
public interface AnimalMBean {
public void eat();
public void sleep();
}
2.Animal.java
package notification;
import javax.management.AttributeChangeNotification;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
public class Animal extends NotificationBroadcasterSupport implements AnimalMBean{
int sequenceNumber=1;
private String status="eat";
@Override
public void eat() {
System.out.println("animal eats ...");
Notification n = new AttributeChangeNotification(this,
sequenceNumber++, System.currentTimeMillis(),
"aniaml eats", "status", "String",
status, "eat");
sendNotification(n);
status="eat";
}
@Override
public void sleep() {
System.out.println("animal sleeps...");
Notification n = new AttributeChangeNotification(this,
sequenceNumber++, System.currentTimeMillis(),
"aniaml sleeps", "status", "String",
status, "sleep");
sendNotification(n);
status="sleep";
}
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[]{
AttributeChangeNotification.ATTRIBUTE_CHANGE
};
String name = AttributeChangeNotification.class.getName();
String description = "An attribute of this MBean has changed";
MBeanNotificationInfo info =
new MBeanNotificationInfo(types, name, description);
return new MBeanNotificationInfo[]{info};
}
}
3.Main.java
package notification;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class Main {
public static void main(String[] args) throws Exception{
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName mxbeanName = new ObjectName("com.example:type=Notification");
Animal mxbean = new Animal();
mbs.registerMBean(mxbean, mxbeanName);
System.out.println("Waiting...");
Thread.sleep(Long.MAX_VALUE);
}
}
每当Animal类中eat或sleep方法是,都会向订阅者发送消息。
4. JConsole 演示
点击Subscribe订阅
点击sleep或eat任意按钮,触发相应操作
在Notifications中会接收相应的消息
四 远程调用jmx。之前以上例子都是运行在本地的。只有本地的JConsole才能访问。
而要注册一个可供远程调用的MBean,必须暴露一个端口可供外部访问。
例如要将例1HelloMBean.java暴露出去
必须在启动参数中加入如下参数
-Dcom.sun.management.jmxremote.port=9999 // 外部访问端口
-Dcom.sun.management.jmxremote.authenticate=false // 关闭验证
-Dcom.sun.management.jmxremote.ssl=false // 关闭ssl
1. 通过JConsole访问
输入远程jmx服务器的ip地址以及jmx暴露的端口号
2. 通过代码远程调用
Main.java
package remote.access;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class Main {
public static void main(String[] args) throws Exception{
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://127.0.0.7:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url);
MBeanServerConnection mbsc=jmxc.getMBeanServerConnection();
ObjectName name = new ObjectName("com.example:type=Hello");
mbsc.invoke(name, "sayHello",null,null);
}
}