基于总线的消息服务(BBMS)的设计与实现

前言

异步事件的通知机制在比较有规模的软件设计中必然会有涉及,比如GUI程序中的事件监听器,应用程序模块之间的通信,以及分布式应用中的消息机制等。如果使用语言原生的对象注册通信,则耦合度不可避免的会增大,也就是说,当时间发生时,A要通知B,则A必须知道B的存在。耦合度的增大在一定程度上必然会影响灵活性。所以,另一种模式就是今天要说的总线模式(BUS Based),即所有的监听器将自己挂在总线上,这些监听器互相之间是无法直接通信的,它们可以向总线上push消息,或者从总线上得到消息,从而实现相互间的通信,当然,这种模式会在性能上有一定的额外开销。

BBMS的主页在google code上:http://code.google.com/p/bbms/

总线机制

基于总线的消息服务(BBMS)的设计与实现_第1张图片

bbms的客户端程序通过将自己注册在BUS Server上来等待异步事件,这个过程可以是本地的,也可以是远程的。本地的BUS可以作为GUI框架中的事件分发者(dispatcher).JMS(Java Message Service)提供企业级的软件模块之间的通信机制,可以使得多个不同的应用集成为一个大型的应用。通过使用BBMS的远程接口,同样可以达到这样的效果。

BBMS的API

 

/**
 * 
 * 
@author  juntao.qiu
 *
 
*/
public   class  Test{
    
public   static   void  main(String[] args)  throws  RemoteException{
        
/*
         * create a notifiable entry, declare that it's care of
         * TIMEOUT, CLOSE, and READY event.
         
*/
        Configuration config 
=   new  RMIServerConfiguration( null 0 );
        CommonNotifiableEntry entry1 
=  
            
new  CommonNotifiableEntry(config,  " client1 "
                MessageTypes.MESSAGE_TIMEOUT 
|  
                MessageTypes.MESSAGE_CLOSE 
|  
                MessageTypes.MESSAGE_READY);
        
        
/*
         * create another notifiable entry, declare that it's care of
         * OPEN, CLOSE, and TIMEOUT event.
         
*/
        CommonNotifiableEntry entry2 
=  
            
new  CommonNotifiableEntry(config,  " client2 "
                MessageTypes.MESSAGE_OPEN 
|  
                MessageTypes.MESSAGE_CLOSE 
|  
                MessageTypes.MESSAGE_TIMEOUT);
        
        
//  register them to the remote Message BUS to listener events
        entry1.register();
        entry2.register();
        
        
//  new a message, of type MESSAGE_OPEN.
        Message msg  =   new  CommonMessage(
                entry1.getId(),
                entry2.getId(),
                MessageTypes.MESSAGE_OPEN,
                
" busying now " );
        
        
//  deliver it to entry2, which is from entry1
        entry1.post(msg);
        
        
//  create a message, of type MESSAGE_CLICKED, the entry2
        
//  does not handle this type, it'll not be deliver to entry2
        Message msgCannotBeReceived  =   new  CommonMessage(
                entry1.getId(),
                entry2.getId(),
                MessageTypes.MESSAGE_CLICKED,
                
" cliked evnet " );
        entry1.post(msgCannotBeReceived);
        
        
try  {
            Thread.sleep(
2000 );
        } 
catch  (InterruptedException e) {
            e.printStackTrace();
        }
        
        
//  re use the message object to send another message entry
        msg.setSource(entry2.getId());
        msg.setTarget(entry1.getId());
        msg.setType(MessageTypes.MESSAGE_READY);
        msg.setBody(
" okay now " );
        entry2.post(msg);
        
        
//  unregister self when all works are done or 
        
//  don't want to listen any more
        entry1.unregister();
        entry2.unregister();
    }
}
API的设计,最好可以做到简单,易用。BBMS也尽力要做到这一点,每一个notifiable(可别通知的)的对象,可以将自己注册到BUS上,当消息抵达时,BUS管理器会调用这个对象上的update方法,进行通知。
This is client2, get message from : client1, it said that : busying now
This is client1, get message from : client2, it said that : okay now

基于总线的消息服务(BBMS)的设计与实现_第2张图片

这个是MS运行的一个简单流程图。

BUS的实现

BUS接口的定义,可以向BUS上注册一个notifiableEntry(可被通知的对象),或者卸载这个对象,同时,可以向BUS中post一条消息。

package  bbms.framework;

/**
 * 
@author  juntao.qiu
 
*/
public   interface  Bus  extends  java.rmi.Remote{
    
/**
     * mount an notifiable entry on bus
     * 
@param  entry
     
*/
    
public   void  mount(NotifiableEntry entry)  throws  java.rmi.RemoteException;
    
    
/**
     * unmount the notifiable entry on bus
     * 
@param  entry
     
*/
    
public   void  unmount(NotifiableEntry entry)  throws  java.rmi.RemoteException;
    
    
/**
     * post a new message to Message Bus
     * 
@param  message
     
*/
    
public   void  post(Message message)  throws  java.rmi.RemoteException;
}
BUS的实现比较有意思,其中维护两个链表,一个是监听器链表,一个是消息链表,挂载在总线上的实体向BUS发送一条消息,这个过程会立即返回。因为发送消息的过程可能由于网络原因或其他原因而延迟,而消息的发送者没有必要等待消息的传递,所以BUS中有一个主动线程,这个线程在BUS中放入新的消息时被唤醒,并对监听器链表进行遍历,将消息分发出去。由于BUS是一个服务级的程序,所以这个主动线程被设计成为一个daemon线程,除非显式的退出或者出错,否则BUS将会一直运行。
     /**
     * 
     * 
@author  juntao.qiu
     * worker thread, dispatch message to appropriate listener
     *
     
*/
    
private   class  Daemon  implements  Runnable{
        
private   boolean  loop  =   true ;
        
public   void  run(){
            
while (loop){
                
if (messages.size()  ==   0 ){
                    
synchronized (messages){
                        
try  {messages.wait();} 
                        
catch  (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                processIncomingMessage();
            }
        }
    }
BUS中的内部工作者线程。它被作为一个Daemon线程:
     private  MessageBus()  throws  RemoteException{
        listeners 
=   new  LinkedList < NotifiableEntry > ();
        messages 
=   new  LinkedList < Message > ();
        Daemon daemon 
=   new  Daemon();
        daemonThread 
=   new  Thread(daemon);
        daemonThread.setPriority(Thread.NORM_PRIORITY 
+   3 );
        daemonThread.setDaemon(
true );
        daemonThread.start();
        
        
while ( ! daemonThread.isAlive());
    }

消息的定义

 

public   interface  Message{
    
public   int  getType();
    
public   void  setType( int  type);
    
    
public  String getTarget();
    
public   void  setTarget(String target);
    
    
public  String getSource();
    
public   void  setSource(String source);
    
    
public  Object getBody();
    
public   void  setBody(Object body);
}
为了更通用起见,消息体部分可以包含任何对象。消息类型参考了windows的消息机制,可以将消息进行复合:
     /*
     * 0x8000 = 1000 0000 0000 0000
     * 0x4000 = 0100 0000 0000 0000
     * 0x2000 = 0010 0000 0000 0000
     * 0x1000 = 0001 0000 0000 0000
     * 
     * it's very useful when you want to combine some messages
     * together, and the user can simply determine what exactly
     * what you want. Refer the implementation of MessageBus.java
     * for more details.
     
*/
    
public   static   final   int  MESSAGE_TIMEOUT  =   0x8000 ;
    
public   static   final   int  MESSAGE_CLICKED  =   0x4000 ;
    
public   static   final   int  MESSAGE_CLOSE  =   0x2000 ;
    
public   static   final   int  MESSAGE_OPEN  =   0x1000 ;
    
    
public   static   final   int  MESSAGE_READY  =   0x0800 ;
    
public   static   final   int  MESSAGE_BUSY  =   0x0400 ;
    
public   static   final   int  MESSAGE_WAIT  =   0x0200 ;
    
public   static   final   int  MESSAGE_OKAY  =   0x0100 ;

总结

BBMS如果进行适当的扩展,可以完全实现JMS规范中涉及到的所有主题,如订阅模式(BBMS现在的实现中只有PTP模式,及点对点的模式,发送消息和接受消息的实体都必须同时在线)。BBMS主要面向的是轻量级的消息传递,比如GUI,分布式的GUI等。如果有兴趣,可以到BBMS的页面上看一看:http://code.google.com/p/bbms/

 

你可能感兴趣的:(设计)