3.2 MXBeans
本节解释一种特殊的MBean,叫做MXBeans。用于将JDK携带的类型组合为自定义的复杂类型
。
MXBean 是一种MBean,它只引用预定义的一组数据类型(例如java.util.Date)。这样,你就能够确保你的MBean能够被任何客户端使用,包括远程客户端,而不需要客户端访问 代表你的MBeans的、和模型相关的classes。MXBeans提供了一种方便的途径,来将相关值绑定到一起,而不需要额外配置客户端来处理相关 classes包。
和标准MBeans的做法一样,一个MXBean的定义为:编写一个叫做 SomethingMXBean
的接口 以及 实现该接口的一个Java类。然而,MXBeans不像标准MBeans,MXBeans不要求Java类必须叫做Something
。在该接口中的每个方法,定义的要么是该MXBean的一个属性,要么是该MXBean的一个操作。也可以用注解@MXBean来
标注Java接口,从而不需要接口的名字以"MXBean"为后缀。
MXBeans存在于 Java 2 Platform, Standard Edition (J2SE) 5.0中,位于 java.lang.management
包下。然而,除了定义在java.lang.management中的
标准MXBeans集合之外,用户现在可以定义他们自己的MXBeans。
MXBeans背后的主要思想是,在MXBean接口中使用的类型,比如java.lang.management.MemoryUsage
被映射到一组标准的类型,也就是定义在javax.management.openmbean
包中的、所谓的"Open Types"。确切的映射规则定义在MXBean规范中。然而,常规原则是,对于诸如int或string之类简单的类型,保持不变;而诸如MemoryUsage
之类的复杂类型,就被映射到标准类型CompositeDataSupport
。
MXBean例子包含下面的文件,可以在jmx_examples.zip
中找到:
QueueSamplerMXBean
接口QueueSampler
类,实现了 MXBean接口。QueueSample
Java类型,由MXBean接口中的getQueueSample()
方法返回。Main,搭建和运行这个例子的程序。
这个MXBean例子使用这些类来执行下面的动作:
定义一个简单的MXBean,用于管理
一个Queue<String>类型的资源。
在MXBean中声明一个getter,
getQueueSample
,当调用该getter时,它对该队列做快照并返回一个Java类QueueSample
,这个QueueSample将下面的值绑定在一起:
做快照的时间
队列的大小
在做快照时,队列的头
在一个MBean Server中注册该 MXBean
MXBean接口
下面的代码展示了例子QueueSamplerMXBean
的MXBean接口:
package com.example; public interface QueueSamplerMXBean { public QueueSample getQueueSample(); public void clearQueue(); }
注意,你声明一个MXBean接口的方式和声明一个标准的MBean接口的方式完全相同。QueueSamplerMXBean
接口声明了一个getter,getQueueSample
,以及一个操作clearQueue
。
定义MXBean操作
QueueSampler是MBean实现,QueueSample是一个自定义的JavaBean!别混淆了。
MXBean操作声明在
QueueSampler
类中,如下:
package com.example; import java.util.Date; import java.util.Queue; 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(); } } }
QueueSampler
定义了 getQueueSample()
这个getter 以及 clearQueue()操作,它们已经声明在其
MXBean接口中了。getQueueSample()
操作返回一个 QueueSample 类型的实例,这个实例由
java.util.Queue
的peek()
和 size()方法返回的值 以及 一个
java.util.Date
实例 构成。
定义MXBean接口返回的Java类型
由QueueSampler
返回的QueueSample
实例定义在
QueueSample
中,如下:
package com.example; import java.beans.ConstructorProperties; import java.util.Date; 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; } }
在 QueueSample
中,MXBean框架会调用QueueSample
中的所有getters,并将返回的实例转化为一个 CompositeData
实例,然后使用@ConstructorProperties
注解 从一个CompositeData
实例中重构一个 QueueSample
实例。
在MBean Server中创建并注册MXBean
到目前位置,我们已经定义了:一个MXBean接口以及该接口的实现类,要返回的Java类型。接着必须创建该MXBean,并将其注册到MBean Server中。这些动作由我们在标准MBean例子中使用的同一个 Main
例子来执行,但是,相关代码在 Standard MBean 课程中并没用显示。
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 { 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); } }
这个 Main
执行下面的动作:
得到 platform MBean server。
为MXBean
QueueSampler
创建一个对象名。创建一个
Queue
实例,供QueueSampler
MXBean来处理。将该
Queu实例喂给新创建的
QueueSampler
MXBean。在MBean Server中注册该MXBean,和注册标准MBean方式完全相同。
Running the MXBean Example(和运行MBean类似,注意下面的第10步关于组合类型的描述)
Running the MXBean Example(和运行MBean类似,注意下面的第10步关于组合类型的描述)
这个MXBean例子使用了来自 jmx_examples.zip 包的classes,你已经在 Standard MBeans 章节使用过这个包了。该例子要求Java SE 6平台。要想运行这个MXBeans例子,请遵循下面的步骤:
1、 如果你还没将jmx_examples.zip保存到你的work_dir目录,那么请保存一下。
2、在终端窗口中,用下面的命令解压例子包。
unzip jmx_examples.zip
3、 在work_dir目录下,编译样例Java类:
javac com/example/*.java
4、启动 Main 程序。一条等待什么事情发生的确认消息就会被生成。
java com.example.Main
5、在相同及其上的不同终端窗口中,启动JConsole。新连接对话框就会被显示,它列举了运行中的、你可以连接的JMX agents。
jconsole
6、在这个新连接对话框中,从上述列表中选择com.example.Main,然后点击 Connect。
你的Java SE平台(也就是运行Main程序的JVM)当前活动的一个汇总就会被显示出来。
7、点击 MBeans 标签页。
这个面板显示了当前注册在MBean Server中的所有的MBeans。
8、 在左边的边框中,展开MBean树中的 com.example 节点。
你可以看见由Main创建并注册的样例MBean QueueSampler。如果你点击 QueueSampler,你就会在MBean树中看到与之相关的属性和操作的节点。
9、展开Attributes节点。
你会看到 QueueSample 属性出现在右边的边框中,其值为javax.management.openmbean.CompositeDataSupport。
双击 CompositeDataSupport 值。
10、 你将看到 QueueSample 的值:date、head和size,因为MXBean框架已经将 QueueSample 实例转化成了 CompositeData。如果你将QueueSampler定义为标准的MBean,而不是MXBean,那么JConsole就无法找到QueueSample类,因为这个类没用出现在JConsole的class path中。如果 QueueSampler 被定义为标准MBean,当你读取QueueSample属性的值的时候,你就会得到一个ClassNotFoundException消息【Java SE 7携带的JConsole会显示"不可用",而不是抛出ClassNotFoundException】。JConsole能够找到QueueSampler这个事实表明:当通过诸如JConsole之类的常规JMX客户端连接到JMX agents的时候,MXBeans很有用。
11、 展开Operations节点
12、 将会显示一个出发 clearQueue 操作的按钮。
点击 clearQueue 按钮。
13、 该方法被成功调用的确认消息就会被显示出来。
再次展开 Attributes 节点,双击 CompositeDataSupport 值。
14、head 和 size 的值已经被重设了。
要想关闭JConsole,选择 Connection -> Exit。
小结:
JMX规范要想确保:
对所有JMX MBean的操作都禁止直接使用这些MBean的reference
任何满足JMX规范的、常规的JMX客户端工具都能够访问JMX Agents,
那么只能对MBean中各方法的参数和返回值的类型做严格限制,这些类型只能是基本类型(String,int,double,float...)以及JMX规范指定的CompositeDataSupport(用于组合基本类型)。稍微复杂一点的类型,比如java.util.Date,就算我们为之定义了public的getter和setter,在显示的时候getter显示的是java.util.Date.toString();然而无法通过setter修改,因为JMX Client工具不知道如何将我们的字符串输入转化成java.util.Date。