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); } }