前言
異步事件的通知機制在比較有規模的軟件設計中必然會有涉及,比如GUI程序中的事件監聽器,應用程序模塊之間的通信,以及分佈式應用中的消息機制等。如果使用語言原生的對象註冊通信,則耦合度不可避免的會增大,也就是說,當時間發生時,A要通知B,則A必須知道B的存在。耦合度的增大在一定程度上必然會影響靈活性。所以,另一種模式就是今天要說的總線模式(BUS Based),即所有的監聽器將自己掛在總線上,這些監聽器互相之間是無法直接通信的,它們可以向總線上push消息,或者從總線上得到消息,從而實現相互間的通信,當然,這種模式會在性能上有一定的額外開銷。
BBMS的主頁在google code上:http://code.google.com/p/bbms/
總線機制
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();
}
}
This is client1, get message from : client2, it said that : okay now
這個是MS運行的一個簡單流程圖。
BUS的實現
BUS接口的定義,可以向BUS上註冊一個notifiableEntry(可被通知的對象),或者卸載這個對象,同時,可以向BUS中post一條消息。
/**
* @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;
}
*
* @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();
}
}
}
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 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);
}
* 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/