3.2 MXBeans

2016-02-23 00:14:00 7,916 1


本节解释一种特殊的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.Queuepeek()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。

上一篇:3.1 标准(Standard)MBeans 下一篇:4.0 通知