Notification 通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知.
这里写一个简单的Server配置例子, 首先定义我们的MBean接口:
- package com.haitao.jmx.mbeans.server;
- /**
- *
- * Server Configure MBean
- *
- * @author haitao.tu
- *
- */
- public interface ServerConfigureMBean {
- public void setPort(int port);
- public int getPort();
- public void setHost(String host);
- public String getHost();
- }
package com.haitao.jmx.mbeans.server;
/**
*
* Server Configure MBean
*
* @author haitao.tu
*
*/
public interface ServerConfigureMBean {
public void setPort(int port);
public int getPort();
public void setHost(String host);
public String getHost();
}
接着,我们会想第一节那样,去实现这个MBean接口,并且继承NotificationBroadcasterSupport,来提供广播服务:
- package com.haitao.jmx.mbeans.server;
- import java.util.concurrent.atomic.AtomicLong;
- import javax.management.AttributeChangeNotification;
- import javax.management.NotificationBroadcasterSupport;
- /**
- * Server Configure
- *
- * @author haitao.tu
- *
- */
- public class ServerConfigure extends NotificationBroadcasterSupport implements ServerConfigureMBean {
- private AtomicLong sequenceNumber = new AtomicLong(1);
- private int port;
- private String host;
- @Override
- public void setPort(int port) {
- int oldPort = this.port;
- this.port = port;
- AttributeChangeNotification notification = new AttributeChangeNotification(
- this,
- sequenceNumber.getAndIncrement(),
- System.currentTimeMillis(),
- AttributeChangeNotification.ATTRIBUTE_CHANGE,
- "Server Port Change",
- "java.lang.Integer",
- oldPort + "",
- this.port + ""
- );
- super.sendNotification(notification);
- }
- @Override
- public void setHost(String host) {
- String oldHost = this.host;
- this.host = host;
- AttributeChangeNotification notification = new AttributeChangeNotification(
- this,
- sequenceNumber.getAndIncrement(),
- System.currentTimeMillis(),
- AttributeChangeNotification.ATTRIBUTE_CHANGE,
- "Server Host Change",
- "java.lang.String",
- oldHost,
- this.host
- );
- super.sendNotification(notification);
- }
- @Override
- public int getPort() {
- return port;
- }
- @Override
- public String getHost() {
- return host;
- }
- }
package com.haitao.jmx.mbeans.server;
import java.util.concurrent.atomic.AtomicLong;
import javax.management.AttributeChangeNotification;
import javax.management.NotificationBroadcasterSupport;
/**
* Server Configure
*
* @author haitao.tu
*
*/
public class ServerConfigure extends NotificationBroadcasterSupport implements ServerConfigureMBean {
private AtomicLong sequenceNumber = new AtomicLong(1);
private int port;
private String host;
@Override
public void setPort(int port) {
int oldPort = this.port;
this.port = port;
AttributeChangeNotification notification = new AttributeChangeNotification(
this,
sequenceNumber.getAndIncrement(),
System.currentTimeMillis(),
AttributeChangeNotification.ATTRIBUTE_CHANGE,
"Server Port Change",
"java.lang.Integer",
oldPort + "",
this.port + ""
);
super.sendNotification(notification);
}
@Override
public void setHost(String host) {
String oldHost = this.host;
this.host = host;
AttributeChangeNotification notification = new AttributeChangeNotification(
this,
sequenceNumber.getAndIncrement(),
System.currentTimeMillis(),
AttributeChangeNotification.ATTRIBUTE_CHANGE,
"Server Host Change",
"java.lang.String",
oldHost,
this.host
);
super.sendNotification(notification);
}
@Override
public int getPort() {
return port;
}
@Override
public String getHost() {
return host;
}
}
在setPort与setHos方法中,首先new了一个AttributeChangeNotification,这个类是javax.management.Notification的子类,而javax.management.Notification
这个类又是java.util.EventObject的子类,由此可以证实上边所说的,JMX通知机制使用了观察者设计模式.
javax.management.Notification是一个JMX的通知核心类,将来需要扩展或者其他JMX自带的消息,均继承自此类.
AttributeChangeNotification根据类名可知,是一个属性改变的通知,造方法参数如下:
Object source, // 事件源,一直传递到java.util.EventObject的source
long sequenceNumber, // 通知序号,标识每次通知的计数器
long timeStamp, // 通知发出的时间戳
String msg, // 通知发送的message
String attributeName, // 被修改属性名
String attributeType, // 被修改属性类型
Object oldValue, // 被修改属性修改以前的值
Object newValue // 被修改属性修改以后的值
根据观察者模式,由事件与广播组成,所以这里继承了NotificationBroadcasterSupport,来提供广播机制,
调用NotificationBroadcasterSupportr的sendNotification(notification) 发送广播,广播会根据注册的观察者
来对观察者进行逐一通知.
sendNotification 在JDK1.6是通过Executor来发送通知,默认调用线程同步发送:
- public NotificationBroadcasterSupport(Executor executor,
- MBeanNotificationInfo... info) {
- this.executor = (executor != null) ? executor : defaultExecutor;
- notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();
- }
public NotificationBroadcasterSupport(Executor executor,
MBeanNotificationInfo... info) {
this.executor = (executor != null) ? executor : defaultExecutor;
notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();
}
- private final static Executor defaultExecutor = new Executor() {
- // DirectExecutor using caller thread
- public void execute(Runnable r) {
- r.run();
- }
- };
private final static Executor defaultExecutor = new Executor() {
// DirectExecutor using caller thread
public void execute(Runnable r) {
r.run();
}
};
如果想用异步发送通知,大家可以在构造方法中传入异步执行的Executor , 例如 ThreadPoolExecutor.
接下来,还得写一个观察者,来接受我们送出的通知:
- package com.haitao.jmx.mbeans.server;
- import javax.management.Notification;
- import javax.management.NotificationListener;
- /**
- * Server Configure Notification Listener
- *
- * @author haitao.tu
- *
- */
- public class ServerConfigureNotificationListener implements
- NotificationListener {
- @Override
- public void handleNotification(Notification notification, Object handback) {
- log("SequenceNumber:" + notification.getSequenceNumber());
- log("Type:" + notification.getType());
- log("Message:" + notification.getMessage());
- log("Source:" + notification.getSource());
- log("TimeStamp:" + notification.getTimeStamp());
- }
- private void log(String message) {
- System.out.println(message);
- }
- }
package com.haitao.jmx.mbeans.server;
import javax.management.Notification;
import javax.management.NotificationListener;
/**
* Server Configure Notification Listener
*
* @author haitao.tu
*
*/
public class ServerConfigureNotificationListener implements
NotificationListener {
@Override
public void handleNotification(Notification notification, Object handback) {
log("SequenceNumber:" + notification.getSequenceNumber());
log("Type:" + notification.getType());
log("Message:" + notification.getMessage());
log("Source:" + notification.getSource());
log("TimeStamp:" + notification.getTimeStamp());
}
private void log(String message) {
System.out.println(message);
}
}
这里只是简单输出了通知内容, 在这个类中我们实现NotificationListener接口,可以看出该接口中只有一个方法,
就是处理消息,顺藤摸瓜,在看一下NotificationListener的接口代码:
- package javax.management;
- import java.util.EventListener;
- /**
- * Should be implemented by an object that wants to receive notifications.
- *
- * @since 1.5
- */
- public interface NotificationListener extends java.util.EventListener {
- /**
- * Invoked when a JMX notification occurs.
- * The implementation of this method should return as soon as possible, to avoid
- * blocking its notification broadcaster.
- *
- * @param notification The notification.
- * @param handback An opaque object which helps the listener to associate information
- * regarding the MBean emitter. This object is passed to the MBean during the
- * addListener call and resent, without modification, to the listener. The MBean object
- * should not use or modify the object.
- *
- */
- public void handleNotification(Notification notification, Object handback) ;
- }
package javax.management;
import java.util.EventListener;
/**
* Should be implemented by an object that wants to receive notifications.
*
* @since 1.5
*/
public interface NotificationListener extends java.util.EventListener {
/**
* Invoked when a JMX notification occurs.
* The implementation of this method should return as soon as possible, to avoid
* blocking its notification broadcaster.
*
* @param notification The notification.
* @param handback An opaque object which helps the listener to associate information
* regarding the MBean emitter. This object is passed to the MBean during the
* addListener call and resent, without modification, to the listener. The MBean object
* should not use or modify the object.
*
*/
public void handleNotification(Notification notification, Object handback) ;
}
可以很清楚的看出继承了java.util.EventListener接口,又一次证实了,JMX通知机制是观察者模式的衍生产品.
好了,所有的功能代码都写完了,下边需要测试一JMX的通知机制:
这里还需要写一个测试用例来支持:
- package com.haitao.jmx.mbeans.server;
- import java.lang.management.ManagementFactory;
- import javax.management.MBeanServer;
- import javax.management.ObjectName;
- public class ServerStartup {
- public static void main(String[] args) throws Exception {
- // 创建MBeanServer
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- // 新建MBean ObjectName, 在MBeanServer里标识注册的MBean
- ObjectName name = new ObjectName("com.haitao.jmx.mbeans.server:type=ServerConfigure");
- // 创建MBean
- ServerConfigure mbean = new ServerConfigure();
- // 在MBeanServer里注册MBean, 标识为ObjectName(com.haitao.jmx.mbeans.server:type=ServerConfigure)
- mbs.registerMBean(mbean, name);
- // 自定义观察者
- ServerConfigureNotificationListener listener = new ServerConfigureNotificationListener();
- // 加入MBeanServer
- mbs.addNotificationListener(name, listener, null, null);
- Thread.sleep(Long.MAX_VALUE);
- }
- }
package com.haitao.jmx.mbeans.server;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class ServerStartup {
public static void main(String[] args) throws Exception {
// 创建MBeanServer
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// 新建MBean ObjectName, 在MBeanServer里标识注册的MBean
ObjectName name = new ObjectName("com.haitao.jmx.mbeans.server:type=ServerConfigure");
// 创建MBean
ServerConfigure mbean = new ServerConfigure();
// 在MBeanServer里注册MBean, 标识为ObjectName(com.haitao.jmx.mbeans.server:type=ServerConfigure)
mbs.registerMBean(mbean, name);
// 自定义观察者
ServerConfigureNotificationListener listener = new ServerConfigureNotificationListener();
// 加入MBeanServer
mbs.addNotificationListener(name, listener, null, null);
Thread.sleep(Long.MAX_VALUE);
}
}
最后,我们开始验证成果:
1.打开%JAVA_HOME%/bin/jconsole连接到本地进程:
2. 进入MBean选项框, 点击左边的树,打开通知:
3. 订阅通知
4. 修改属性,产生通知
5. 验证通知
OK, 学习笔记二写完了,回想下一,
1. JMX中要定义接口必须以xxxMBean的规范定义
2. 得有类实现xxxMBean接口
3. 在实现类中可以继承NotificationBroadcasterSupport来支持通知机制
4. 可以通过jconsole来验证
:)