为了产生通知,MBean必须实现NotificationEmitter接口或者继承NotificationBroadcasterSupport类。为了发送通知,你需要构造javax.management.Notification类或者其子类(例如AttributeChangedNotification)的实例,并将这个实例传递给NotificationBroadcasterSupport.sendNotification方法。
每一个通知都有源。源就是产生这个通知的MBean的对象名。
每一个通知都有一个序列号。当通知的顺序很要紧并且处理通知时存在次序错乱的风险时,这个序列号可以用于对来自同一个源的通知进行排序。序列号可以是零,但从给定的MBean发来的通知的序列号最好是依次递增的。
Hello MBean实现了标准MBean,实际上也实现了通知机制。然而,在那一节课中为了简单,把这些代码忽略了。Hello类的完整代码如下所示:
package com.example;
import javax.management.*;
public class Hello
extends NotificationBroadcasterSupport
implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}
public int add(int x, int y) {
return x + y;
}
public String getName() {
return this.name;
}
public int getCacheSize() {
return this.cacheSize;
}
public synchronized void setCacheSize(int size) {
int oldSize = this.cacheSize;
this.cacheSize = size;
System.out.println("Cache size now " + this.cacheSize);
Notification n = new AttributeChangeNotification(this,
sequenceNumber++, System.currentTimeMillis(),
"CacheSize changed", "CacheSize", "int",
oldSize, this.cacheSize);
sendNotification(n);
}
@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};
}
private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
private long sequenceNumber = 1;
}
Hello类继承了NotificationBroadcasterSupport类。而NotificationBroadcasterSupport类实现了NotificationEmitter接口。操作和属性与标准MBean示例中是一样的,除了cacheSize属性的set方法定义了一个oldSize变量值,这个变量值用于记录set操作之前的cacheSize属性值。
通知是由AttributeChangeNotification类的实例n构造的,AttributeChangeNotification类继承自javax.management.Notification类。通知是在定义setCacheSize()方法时,由下列信息构造的,这些信息作为参数传递给AttributeChangeNotification的构造函数:
- 通知源的对象名,即Hello MBean,用this表示
- 一个序列号,即sequenceNumber,被设置为1,并且是递增的
- 时间戳
- 通知消息的内容
- 发生改变的属性的名称,在这个示例中是cacheSize
- 发生改变的属性的类型
- 旧的属性值,在这个示例中是oldValue
- 新的属性值,在这个示例中是this.cacheSize
然后,通知n被传递给NotificationBroadcasterSupport.sendNotification()方法。
最后,定义一个给定通知类型的MBeanNotificationInfo实例用于描述MBean产生的不同通知实例的特点。在这个示例中,通知的类型是AttributeChangeNotification。
运行MBean通知示例
你将再一次使用JConsole与Hello MBean进行交互,这一次是用于发送和接收通知。这个示例需要Java SE6。
- 如果这一步还没有做,那就保存JMX例子的压缩包jmx_examples.zip到你的工作目录work_dir。
- 在命令行或者终端使用下面的命令解压缩这个包:unzip jmx_examples.zip。
- 在work_dir目录下编译例子中所有类:javac com/example/*.java。
- 启动Main应用:java com.example.Main。确认显示Main正在等待一些事情发生。
- 在同一台机器上打开一个新的命令行或者终端窗口,启动JConsole。新建连接对话框将会显示出来,列表中显示出可以连接的正在运行的JMX代理。
- 在新建连接对话框中,从列表中选择com.example.Main中,并点击connect。这时,平台的当前活动的概述将会显示出来。
- 点击MBean标签,这个面板将会显示所有当前注册到MBean服务器中的MBean。
- 在左边的MBean树中,展开com.example节点。你会看到在Main中创建并注册的MBean Hello。如果你点击Hello,你会在MBean树中看到它的“通知”节点。
- 在MBean树中,展开Hello MBean的“通知”节点。注意面板是空白的。
- 点击“订阅”按钮。收到的通知的当前数量会显示在通知节点标签上。
- 在MBean树中,展开Hello MBean的“属性”节点。将cacheSize属性值改为150。在你启动Main的命令行或者终端窗口中,确认显示出了属性改变的消息。注意,通知节点上的显示的通知数量已经变为1。
- 再一次展开MBean树中的Hello MBean的“通知”节点。通知的详细信息显示出来了。
- 要想关闭JConsole,选择 连接->退出。