`
tuhaitao
  • 浏览: 379266 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

JMX学习笔记(二)-Notification

    博客分类:
  • java
阅读更多

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

 

 

接着,我们会想第一节那样,去实现这个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;
	}

}
 

 

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

 

 

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

}
 

这里只是简单输出了通知内容, 在这个类中我们实现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) ;
}
 

可以很清楚的看出继承了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);
	}
	
}

 

最后,我们开始验证成果:

 

1.打开%JAVA_HOME%/bin/jconsole连接到本地进程:

 

 

jconsole

 

2. 进入MBean选项框, 点击左边的树,打开通知:

 

 

 

3. 订阅通知

 

 

 

4. 修改属性,产生通知

 

 

 

 

5. 验证通知

 

 

 

OK, 学习笔记二写完了,回想下一, 

 

1. JMX中要定义接口必须以xxxMBean的规范定义

2. 得有类实现xxxMBean接口

3. 在实现类中可以继承NotificationBroadcasterSupport来支持通知机制

4. 可以通过jconsole来验证

 

:)

分享到:
评论
1 楼 sswh 2013-11-27  
代码中的示例 和 后面的“验证通知”完全没有一点关系。

不知道JConsole(或者JMX客户端)是怎样对一个MBean的事件进行订阅的?

而不是类似下面的代码:
// 加入MBeanServer 
mbs.addNotificationListener(name, listener, null, null);




相关推荐

Global site tag (gtag.js) - Google Analytics