JMX学习笔记(二)-Notification

Notification   通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知.

 

 

这里写一个简单的Server配置例子, 首先定义我们的MBean接口:

 

 

Java代码 复制代码
  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. /**  
  4.  *   
  5.  * Server Configure MBean  
  6.  *   
  7.  * @author haitao.tu  
  8.  *  
  9.  */  
  10. public interface ServerConfigureMBean {   
  11.   
  12.     public void setPort(int port);   
  13.        
  14.     public int getPort();   
  15.        
  16.     public void setHost(String host);   
  17.        
  18.     public String getHost();   
  19.        
  20. }  
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,来提供广播服务:

 

 

Java代码 复制代码
  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. import java.util.concurrent.atomic.AtomicLong;   
  4.   
  5. import javax.management.AttributeChangeNotification;   
  6. import javax.management.NotificationBroadcasterSupport;   
  7.   
  8. /**  
  9.  * Server Configure  
  10.  *   
  11.  * @author haitao.tu  
  12.  *  
  13.  */  
  14. public class ServerConfigure extends NotificationBroadcasterSupport implements ServerConfigureMBean {   
  15.        
  16.     private AtomicLong sequenceNumber = new AtomicLong(1);   
  17.   
  18.     private int port;   
  19.   
  20.     private String host;   
  21.   
  22.     @Override  
  23.     public void setPort(int port) {   
  24.         int oldPort = this.port;   
  25.         this.port = port;   
  26.         AttributeChangeNotification notification = new AttributeChangeNotification(   
  27.                 this,   
  28.                 sequenceNumber.getAndIncrement(),   
  29.                 System.currentTimeMillis(),   
  30.                 AttributeChangeNotification.ATTRIBUTE_CHANGE,   
  31.                 "Server Port Change",   
  32.                 "java.lang.Integer",   
  33.                 oldPort + "",   
  34.                 this.port + ""  
  35.                 );   
  36.         super.sendNotification(notification);   
  37.     }   
  38.   
  39.     @Override  
  40.     public void setHost(String host) {   
  41.         String oldHost = this.host;   
  42.         this.host = host;   
  43.         AttributeChangeNotification notification = new AttributeChangeNotification(   
  44.                 this,   
  45.                 sequenceNumber.getAndIncrement(),   
  46.                 System.currentTimeMillis(),   
  47.                 AttributeChangeNotification.ATTRIBUTE_CHANGE,   
  48.                 "Server Host Change",   
  49.                 "java.lang.String",   
  50.                 oldHost,   
  51.                 this.host   
  52.                 );   
  53.         super.sendNotification(notification);   
  54.     }   
  55.   
  56.     @Override  
  57.     public int getPort() {   
  58.         return port;   
  59.     }   
  60.   
  61.     @Override  
  62.     public String getHost() {   
  63.         return host;   
  64.     }   
  65.   
  66. }  
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来发送通知,默认调用线程同步发送:

 

 

Java代码 复制代码
  1. public NotificationBroadcasterSupport(Executor executor,   
  2.                       MBeanNotificationInfo... info) {   
  3.     this.executor = (executor != null) ? executor : defaultExecutor;   
  4.   
  5.     notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();   
  6.     }  
public NotificationBroadcasterSupport(Executor executor,
					  MBeanNotificationInfo... info) {
	this.executor = (executor != null) ? executor : defaultExecutor;

	notifInfo = info == null ? NO_NOTIFICATION_INFO : info.clone();
    }

 

 

 

Java代码 复制代码
  1. private final static Executor defaultExecutor = new Executor() {   
  2.         // DirectExecutor using caller thread   
  3.         public void execute(Runnable r) {   
  4.         r.run();   
  5.         }   
  6.     };   
private final static Executor defaultExecutor = new Executor() {
	    // DirectExecutor using caller thread
	    public void execute(Runnable r) {
		r.run();
	    }
	}; 

 

 

如果想用异步发送通知,大家可以在构造方法中传入异步执行的Executor , 例如 ThreadPoolExecutor.

 

接下来,还得写一个观察者,来接受我们送出的通知:

 

 

Java代码 复制代码
  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. import javax.management.Notification;   
  4. import javax.management.NotificationListener;   
  5.   
  6. /**  
  7.  * Server Configure Notification Listener  
  8.  *   
  9.  * @author haitao.tu  
  10.  *   
  11.  */  
  12. public class ServerConfigureNotificationListener implements  
  13.         NotificationListener {   
  14.   
  15.     @Override  
  16.     public void handleNotification(Notification notification, Object handback) {   
  17.         log("SequenceNumber:" + notification.getSequenceNumber());   
  18.         log("Type:" + notification.getType());   
  19.         log("Message:" + notification.getMessage());   
  20.         log("Source:" + notification.getSource());   
  21.         log("TimeStamp:" + notification.getTimeStamp());   
  22.     }   
  23.   
  24.     private void log(String message) {   
  25.         System.out.println(message);   
  26.     }   
  27.   
  28. }  
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的接口代码:

 

 

Java代码 复制代码
  1. package javax.management;   
  2.   
  3.   
  4. import java.util.EventListener;   
  5.   
  6.   
  7. /**  
  8.  * Should be implemented by an object that wants to receive notifications.  
  9.  *  
  10.  * @since 1.5  
  11.  */  
  12. public interface NotificationListener extends java.util.EventListener   {    
  13.   
  14.     /**  
  15.     * Invoked when a JMX notification occurs.  
  16.     * The implementation of this method should return as soon as possible, to avoid  
  17.     * blocking its notification broadcaster.  
  18.     *  
  19.     * @param notification The notification.      
  20.     * @param handback An opaque object which helps the listener to associate information  
  21.     * regarding the MBean emitter. This object is passed to the MBean during the  
  22.     * addListener call and resent, without modification, to the listener. The MBean object   
  23.     * should not use or modify the object.   
  24.     *  
  25.     */  
  26.     public void handleNotification(Notification notification, Object handback) ;   
  27. }  
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的通知机制:

 

这里还需要写一个测试用例来支持:

 

 

Java代码 复制代码
  1. package com.haitao.jmx.mbeans.server;   
  2.   
  3. import java.lang.management.ManagementFactory;   
  4.   
  5. import javax.management.MBeanServer;   
  6. import javax.management.ObjectName;   
  7.   
  8. public class ServerStartup {   
  9.   
  10.     public static void main(String[] args) throws Exception {   
  11.         // 创建MBeanServer   
  12.         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();   
  13.         // 新建MBean ObjectName, 在MBeanServer里标识注册的MBean   
  14.         ObjectName name = new ObjectName("com.haitao.jmx.mbeans.server:type=ServerConfigure");   
  15.         // 创建MBean   
  16.         ServerConfigure mbean = new ServerConfigure();   
  17.         // 在MBeanServer里注册MBean, 标识为ObjectName(com.haitao.jmx.mbeans.server:type=ServerConfigure)   
  18.         mbs.registerMBean(mbean, name);   
  19.         // 自定义观察者   
  20.         ServerConfigureNotificationListener listener = new ServerConfigureNotificationListener();   
  21.         // 加入MBeanServer   
  22.         mbs.addNotificationListener(name, listener, nullnull);   
  23.         Thread.sleep(Long.MAX_VALUE);   
  24.     }   
  25.        
  26. }  
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来验证

 

本文原帖:http://tuhaitao.javaeye.com/blog/804972

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值