`
scanfprintf123
  • 浏览: 80262 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JMX Notification Model

阅读更多

  Since Notification Model is actually a typical observer model, I will start with the observer model, and evolve it to the Notification Model in JMX.

 

  Simply, the observer pattern allows one object (the observer) to watch another object ( the subject), actually the observer and the subject form the publish-subscribe relationship. And through this pattern, the subject can register and unregister the observer, and when event of some type occurs, subject can also inform the corresponding observer of an occuring event. And from the following picture, we can see that observer pattern consist of a publisher, a listener and a event.



 Ok, after we have checked the big picture of Observer pattern, I would like to show you an simple concreate example of observer pattern.

 

public interface IPublisher {

	public void register(IListener li);
	
	public void unregister(IListener li);
	
	public void notifyEvent(IEvent event);
}


public interface IListener {
	public void handleEvent(IEvent event);
}

public interface IEvent {
	public void setSource(Object obj);
	
	public Object getSource();
	
	public void setType(String type);
	
	public String getType();
}

 

   Then our implementation:

  

public class PublisherImpl implements IPublisher {
	List<IListener> listenerList=new ArrayList<IListener>();
	public void notifyEvent(IEvent event) {
		for(IListener li:listenerList)
			li.handleEvent(event);
	}

	public void register(IListener li) {
		listenerList.add(li);
	}

	public void unregister(IListener li) {
		listenerList.remove(li);
	}
}

public class EventImpl implements IEvent {
	private Object source;
	private String type;
	public Object getSource() {
		return source;
	}

	public String getType() {
		return type;
	}

	public void setSource(Object obj) {
		this.source=obj;
	}

	public void setType(String type) {
		this.type=type;
	}

}

 

  Ok, when we done this, we need to check them:

 

            public static void main(String[] args) {

		IPublisher publisher = new PublisherImpl();

		// add new listener
		publisher.register(new IListener() {
			public void handleEvent(IEvent event) {
				System.out.println(event.getType());
			}
		});
		
		//notify a print event
		publisher.notifyEvent(new EventImpl());
	}

   Wow, it is easy, isn't it?

 

    But what would happen if we unregister a listener when the publisher is notifying all the registered listener of the occurrence of the event. One possible situation is that, the listener has been unregistered, but it is still notified by the publisher. For this situation, some people would say, use synchronization. Yeah, you got it. Synchronization can solve this problem. Let's modify our existing PublisherImpl:

public class PublisherImpl implements IPublisher {
	List<IListener> listenerList=new ArrayList<IListener>();
	public synchronized void notifyEvent(IEvent event) {
		for(IListener li:listenerList)
			li.handleEvent(event);
	}

	public synchronized void register(IListener li) {
		listenerList.add(li);
	}

	public synchronized void unregister(IListener li) {
		listenerList.remove(li);
	}
}

 

   Well, things seem fine now, but synchronization brings in some other problems, for instance, thread A is notifying the registered listeners now, and meanwhile thread B and C want to register a listener to the publisher, since these methods are synchronized, thread B and C have to wait until thread A finishes its notifying task. This would causes the performance reduction. After analyzing the problem, we find that why thread B and C have to wait until all the listeners in thread A finish their handling, they dont care about this, what thread B and C do care is to have their listners registered in the publisher, but in order to avoid the first problem we described above, we can just get rid of the synchronization of the notifyEvent() method, but we can minimize the synchronized scope and separate the operations on listnerList from the notifying process. As the below shows:

public void notifyEvent(IEvent event) {
		// local listnerList,copy from listenerList
		IListener[] listners = null;
		synchronized (this) {
			listners = Arrays.copyOf(listenerList.toArray(new IListener[0]),
					listenerList.size());
		}
		for (IListener li : listners)
			li.handleEvent(event);
	}

  But this still can't solve the performance problem, let's think of such a listener registered in the publisher:

 

public class ListernerImpl implements IListener {
	public void handleEvent(IEvent event) {
		while(true)
		{}
	}
}

 

   This kind of listener would make all the following listeners unaccessible. So the best solution is to use a Thread pool to handle the notifying process. Since we have Executor that matches our conditions in JDK5.0, we'll use it here. First, we need to expand the IPublisher interface with IExecutorHandler interface, then the IPublisher can have the ability of handling the Executor.

public interface IExecutorHandler {
	public void setExecutor(Executor executor);
	public Executor getExecutor();
}

public interface IPublisher extends IExecutorHandler {
                ...
}

 

  And then implements the IExecutorHandler in PublisherImpl:

public class PublisherImpl implements IPublisher {
	private Executor executor;
	private Executor defaultExecutor=new Executor(){
		public void execute(Runnable command) {
			//default Executor using caller thread
			command.run();
		}
	};
	
	public Executor getExecutor() {
		return executor!=null?executor:defaultExecutor;
	}

	public void setExecutor(Executor executor) {
		this.executor=executor!=null?executor:defaultExecutor;
	}
                
                // the original code
                ...
	
	}

    

    Since we are using the Executor interface here, it requires a Runnable object for its method. Therefore, we need to wrap our IListener and IEvent as a SendNotifJob for Executor to use.

   

public class PublisherImpl implements IPublisher {
	...

	public void notifyEvent(IEvent event) {
		// local listnerList,copy from listenerList
		IListener[] listners = null;
		synchronized (this) {
			listners = Arrays.copyOf(listenerList.toArray(new IListener[0]),
					listenerList.size());
		}
		for (IListener li : listners)
			getExecutor().execute(new SendNotifJob(li,event));
	}

	...
	
	private class SendNotifJob implements Runnable
	{
		IListener listener; 
		IEvent event;
		public SendNotifJob(IListener listener,IEvent event)
		{
			this.listener=listener;
			this.event=event;
		}
		public void run() {
			listener.handleEvent(event);
		}
	}
}

 

    Finally, we can set our executor before we notify the listener of the event.

   

                                ...
		//set executor
		publisher.setExecutor(Executors.newFixedThreadPool(10));
		
		//notify a print event
		publisher.notifyEvent(new EventImpl());

 

    Here we use a thread pool which contains 10 threads as the Executor.

   

    Well, everything seems fine now. But for synchronization in our example, I am wonderring why we have to take the publisher instance as a lock, as opposed to the listenerList itself. When we use synchronization, we have to ask ourselves a question, what are we protecting? In our case, we need to protect lisenerList in the Publisher instance from being accessed by different threads at the same time, not the publisher instance. Thus, I think we should refactory our code as below:

                List<IListener> listenerList = new ArrayList<IListener>();

	public void notifyEvent(IEvent event) {
		// local listnerList,copy from listenerList
		IListener[] listners = null;
		synchronized (listenerList ) {
			listners = Arrays.copyOf(listenerList.toArray(new IListener[0]),
					listenerList.size());
		}
		for (IListener li : listners)
			getExecutor().execute(new SendNotifJob(li,event));
	}

	public void register(IListener li) {
                             synchronized (listenerList ) {
		listenerList.add(li);
                             }
	}

	public synchronized void unregister(IListener li) {
	             synchronized (listenerList ) {
		listenerList.remove(li);
                             }
	}

 

   And in fact, we dont have to handle the synchronization of the listenerList by ourselves, besides that, no matter when we add a method related to listenerList, we have to repeat the same synchronization code. For instance, if we want to unregister all listeners, we need to add a unregisterAll() method.

  

                public void unregisterAll()
	{
		synchronized (listenerList) {
			//remove listenerList
		}
	}

   

    If you're familiar with design pattern, you must know strategy pattern can solve this problem. Then you can get rid of the repetitive synchronization code. Like the following picture shows:

   

 

Fortunately, we have existent lib to provide synchronized list, we can replace the original ArrayList with following one:

 

List<IListener> listenerList = Collections.synchronizedList(new ArrayList<IListener>());

   But I recommend you to use CopyOnWriteArrayList, no matter what operations(set,add and so on) on this list, it would make a fresh copy of underlying array of this list. And more important, when created its corrsponding iterator, it would hold a reference of that underlying array of this list on that point.

  

#CopyOnWriteArrayList
    public ListIterator<E> listIterator() {
        return new COWIterator<E>(getArray(), 0);
    }

   So the iterator of this list wont be interfered during its lifetime, that is to say, it won't be interfered during the publisher's notifying process.

  

   As we metioned above, when using CopyOnWriteArrayList, we not only can remove the repetitive synchronization code, but also can get rid of the copy code during notifying process.

 

public class PublisherImpl implements IPublisher {
	...
	
	List<IListener> listenerList = new CopyOnWriteArrayList<IListener>();

	public void notifyEvent(IEvent event) {
		for (IListener li : listenerList)
			getExecutor().execute(new SendNotifJob(li,event));
	}

	public  void register(IListener li) {
		listenerList.add(li);
	}

	public  void unregister(IListener li) {
		listenerList.remove(li);
	}
	
	...
}

 

   All right, now let's take a look at the how to use listener. We all know that, we might have many listeners registered in the publisher, and we might have different type of event. And generally speaking, a listener only respond to a specific event type.

   

public void handleEvent(IEvent event) {
		 if(event.getType().equals("SomeType"))
		  {
	                        //do sth
		   }}

     And sometimes it does not only depend on the event's type, it might depends on other event attributes too. So sometimes we have to add many if sentences in our listeners, can't we just separate the filterable action from the business logic we do in the listener? Of course, we can, use filter. In most of the situations, a listener can have its own filter, in order to meet that demand, we need to improve our IPublisher.

    First, add a new IFilter interface

   

public interface IFilter {
	public void isEventEnable(IEvent event);
}

 

   Secondly, modify our IPublisher and PublisherImpl class.

  

public interface IPublisher extends IExecutorHandler {

	public void register(IListener li,IFilter filter);
	
	public void unregister(IListener li,IFilter filter);
	
	...
}

 

    Because we have added a new IFilter parameter to the register() method and unregister() method, we need to hold the reference to the IFilter object too. Therefore, we wrap IListener object and IFilter object in a new ListenerInfo object.

  

   

private class ListenerInfo {
		IListener listener;
		IFilter filter;

		public ListenerInfo(IListener listener, IFilter filter) {
			this.listener = listener;
			this.filter = filter;
		}

		public boolean equals(Object obj) {
			{
				if (!(obj instanceof ListenerInfo))
					return false;
				ListenerInfo li = (ListenerInfo) obj;
				return (li.listener.equals(listener) && li.filter
						.equals(filter));
			}
		}
	}

 

   Then our modified PublisherImpl:

  

List<ListenerInfo> listenerList = new CopyOnWriteArrayList<ListenerInfo>();

	public void notifyEvent(IEvent event) {
		for (ListenerInfo li : listenerList) {
			if (li.filter != null && li.filter.isEventEnable(event))
				getExecutor().execute(new SendNotifJob(li.listener, event));
		}
	}

	public void register(IListener li, IFilter filter) {
		listenerList.add(new ListenerInfo(li, filter));
	}

	public void unregister(IListener li, IFilter filter) {
		listenerList.remove(new ListenerInfo(li, filter));
	}

 

   The last is about how we use the filter:

  

	// add new listener
		publisher.register(new IListener() {
			public void handleEvent(IEvent event) {
				System.out.println(event.getType());
			}
		}, new IFilter() {
			public boolean isEventEnable(IEvent event) {
				return event.getType().equals("someType");
			}
		});

 

   After we introduced the observer pattern, it's time to involve JMX notification in. If we see the class diagram of JMX Notification Model, we'll find that it is as alike as the observer pattern we metioned above.

  

A NotificationBroadcaster is actually a IPublisher, a NotificationListener is a IListener, a NotificationFilter is a IFilter and a Notification is a IEvent. As we said, NotificationBroadcaster  can add, remove listener, and send notification:



 Pay attention to addNotificationListener() method, you will notice there has a third parameter handback object, this object will be sent to NotificationListener without modification when a notification is emitted. As javadoc said, it is used to associate information regarding the MBean emitter.

 And the NotificationFilter is almost the same as IFilter as below:



 

Now let's take a look at the Notification: Notification has several constructors which hold the required info.

public Notification(String type, Object source, long sequenceNumber, long timeStamp, String message) 

public Notification(String type, Object source, long sequenceNumber, long timeStamp)

public Notification(String type, Object source, long sequenceNumber, String message)

public Notification(String type, Object source, long sequenceNumber)

 

  • type->the notification type, such as 'jmx.monitor.error.threshold', of course,you can define your custom notification type.
  • source->the source object which send the notification
  • sequenceNumber->sometimes we need this number to indicate the order in relation of events from the source.
  • timeStamp->the notification emission date
  • message->the detailed message

 What we should pay attention to is the NotificationBroadcasterSupport class, if you look into the code of it, you would find that the PublisherImpl class described above and it are so much alike, well, I admit that I intentionally evolved the PublisherImpl class to NotificationBroadcasterSupport since this is a article of JMX Notification Model. You can use the JMX Notification Model like the Observer pattern we described above.

 

      Before we finish this article, I would like you to know there still exist a problem in our observer example, as we know, every operations(add,set and so on) on the CopyOnWriteArrayList will cause a fresh copy, it is not good, is it? It is ok when there are not too many listeners registered in the publisher, but what if the size of the registered listeners is 1000 or 10000? If so, that would be a problem to make copy frequently. Now I want to recommend you a good solution that can ease the performance which I learn from others. That is, use a linked list instead of CopyOnWriteArrayList, of course, it must be synchronized, when adding a new listener into it, just insert the incoming listener on the first place of the linked list, then we can avoid making fresh copy when registering. We only make copy when unregistering the listener.

 

Register a new listener to the linked list:



 

Unregister a listener during the notifying process



 By this way, in addition to avoid making copy when registering new listener, but also avoid the unregister problem when unregistering listeners.
 

  • 大小: 8.4 KB
  • 大小: 6.2 KB
  • 大小: 8 KB
  • 大小: 5.9 KB
  • 大小: 1.6 KB
  • 大小: 1.4 KB
  • 大小: 5.3 KB
  • 大小: 11.1 KB
2
0
分享到:
评论
1 楼 hugo 2009-10-05  
非常精彩,期待更多jmx相关文章

相关推荐

    jmx_tristan_notification

    标题“jmx_tristan_notification”涉及的是Java管理扩展(Java Management Extensions, JMX)技术,一个用于管理和监控Java应用程序的框架。在这个特定的上下文中,它可能与博主Tristan分享的一篇博客文章有关,该...

    jmx监控weblogic,tomcat,websphere源码

    4. **Notification**: JMX支持发布/订阅模型,MBeans可以发送通知到感兴趣的客户端,使得实时监控成为可能。 通过JMX,开发者可以实现自定义的监控解决方案,例如收集性能指标、触发警报或自动调整系统设置。这个...

    JAVA JMX 学习资料

    JMX支持Notification机制,允许MBeans向其他组件发送事件通知,如性能阈值超限、状态改变等。 5. **JMX Connectors**: JMX Connectors提供了连接到MBean Server的途径,有多种类型的连接器,如RMI(Remote ...

    JMX实战 JMX开发

    JMX实战 书中不仅有对于基础知识的介绍,还有对于JMX开发中重大的体系架构问题的深入探讨,总结了大量JMX开发中的设计模式,并讨论了框架、安全性与性能等等。书中提供了几个典型的例子,兼顾各种开发平台,这些...

    jmx三种访问方式

    Java Management Extensions(JMX)是Java平台中用于管理和监控应用程序、操作系统、网络设备等资源的一种标准框架。通过JMX,开发者可以创建管理代理(MBeans),这些代理暴露了各种管理特性,使得系统管理员可以...

    jmx监控activeMQ监控

    jmx监控ActiveMQ监控 jmx(Java Management Extensions)是一种Java技术,为Java应用程序提供了管理和监控的功能。ActiveMQ是Apache软件基金会下的一个开源消息队列系统,提供了高效、可靠的消息传递服务。在生产...

    最简单JMX例子

    4. **Notification**:MBean可以发送通知事件,告知管理器其状态的改变或其他重要事件。 5. **Connector**:连接器提供客户端与MBeanServer之间的通信,允许客户端访问和管理MBean。 在"jxmdemo"这个压缩包中,很...

    JMX一步一步来,快速学会开发JMX应用

    【JMX 一步步来】 JMX(Java Management Extensions)是一个用于在Java应用程序中添加管理和监控功能的框架。它提供了一套标准的接口和服务,使得开发者能够轻松地在Java应用中集成管理和监控的能力。JMX的核心概念...

    JMX、MXBean学习

    在JMX中,MBeans主要有三种类型:Standard MBeans、Dynamic MBeans和Model MBeans。Standard MBeans是预定义了管理接口的类,Dynamic MBeans则可以在运行时动态定义其管理接口,而Model MBeans是一种抽象层,可以将...

    JMX小例子以及介绍

    - **Notification**: JMX允许MBean发送通知,这使得其他MBeans或管理工具可以订阅并接收有关系统状态变化的信息。 - **JMX连接器**: 连接器是JMX与外部世界交互的桥梁,它们允许管理应用程序通过JMX API连接到MBean...

    JMX配置与使用

    Java Management Extensions(JMX)是Java平台上的一个标准,它提供了管理和监视应用程序、服务、硬件设备等资源的能力。JMX允许开发人员创建可管理和监视的组件,并将它们集成到Java应用中。以下是对JMX配置与使用...

    jmx-1.2.1(jmxri+jmxtools) jar

    这个"jmx-1.2.1(jmxri+jmxtools) jar"包含了JMX的两个核心组件:JMX Remote Interface (jmxri) 和 JMX Tools。 1. **JMX Remote Interface (jmxri)**: JMX Remote Interface 是JMX框架的一部分,它允许远程访问和...

    jmx学习资料

    4. **Notification**: JMX支持Notification机制,MBeans可以发布通知,其他组件可以通过订阅来接收这些通知,实现事件驱动的管理。 5. **JMX Connectors**: 这是JMX与外部世界的桥梁,提供了多种标准的协议和API,...

    Hbase和Hadoop JMX监控实战

    JMX(Java Management Extensions)是一种Java平台标准,用于管理和监控应用程序。在本实战中,我们将深入探讨如何利用JMX对HBase和Hadoop进行监控,以确保系统的稳定性和性能。 首先,我们需要理解HBase。HBase是...

    Fiddler导出jmx文件

    Fiddler导出jmx文件,解决Fiddler导出文件中 没有jmx文件选项,各个版本fiddler都适用

    jmx-tools.zip

    Java Management Extensions(JMX)是Java平台上的一个标准技术,用于管理和监控应用程序、服务和设备。JMX提供了创建、配置、查询和管理管理对象(MBeans)的能力,这些对象可以代表任何可管理的资源,从操作系统到...

    TongWeb7的JMX监控.doc

    在运维过程中,JMX(Java Management Extensions)监控是一个非常重要的工具,可以帮助我们实时查看和管理应用程序的状态,以及诊断和解决问题。本文将详细介绍如何使用 JMX 监控 TongWeb7。 首先,要开启 JMX 监控...

    jmx中包含的主要API

    这个类继承自 `Notification`,用于表示客户端连接的开启、关闭、失败或通知丢失等事件。这些事件由连接器服务器(`JMXConnectorServer` 实例)和连接器客户端(`JMXConnector` 实例)发出。例如,类型为 `jmx....

Global site tag (gtag.js) - Google Analytics