mina是一款網(wǎng)絡(luò)應(yīng)用框架, 它是基于java nio 的 通訊框架, 提供抽象的事件驅(qū)動異步的api掀虎。
mina 基本架構(gòu):
大致上分為三層IoSerivce, Filter, Handler
首先我們來看一下Filter
事件
前面說過颓遏, mina 是基于事件驅(qū)動的, 所以我們先來看一下mina定義了那些事件:
IoEventType 類中定義了如下枚舉變量:
public enum IoEventType {
SESSION_CREATED, session 創(chuàng)建
SESSION_OPENED, session 開啟
SESSION_CLOSED, session 關(guān)閉
MESSAGE_RECEIVED, 消息收到
MESSAGE_SENT, 消息發(fā)送
SESSION_IDLE, session 閑置
EXCEPTION_CAUGHT, 發(fā)生異常異常捕獲
WRITE, 寫事件 out
CLOSE, 關(guān)閉事件
}
這些事件對于用戶使用者來說無需關(guān)心粮宛。
以上IoEventType僅是事件的類型(事件的屬性)窥淆, mina對于事件是通過IoEvent對象進行封裝的。
來看一下IoEvent 都有哪些方法:
public class IoEvent implements Runnable {
private final IoEventType type;
private final IoSession session;
private final Object parameter;
public IoEvent(IoEventType type, IoSession session, Object parameter)
public IoEventType getType()
public IoSession getSession()
public Object getParameter()
public void run() {
fire();
}
public void fire()
我們看到IoEvent 實現(xiàn)了Runnable巍杈,也就是說這個對象會交給多線程去執(zhí)行run方法忧饭。
在run方法中我們看到執(zhí)行的是fire(), 也就是具體的任務(wù)了。
下面來看一下fire中做的事情筷畦, 首先看以下IoEvent 中 具體做了哪些事情词裤, 再看一下其子類IoFilterEvent又做了哪些事情刺洒。 后面我會講IoFilterEvent 的作用是什么, 在哪里用到吼砂。
switch (getType()) {
case MESSAGE_RECEIVED:
getSession().getFilterChain().fireMessageReceived(getParameter());
break;
case MESSAGE_SENT:
getSession().getFilterChain().fireMessageSent((WriteRequest) getParameter());
break;
case WRITE:
getSession().getFilterChain().fireFilterWrite((WriteRequest) getParameter());
break;
case CLOSE:
getSession().getFilterChain().fireFilterClose();
break;
....
}
其實做的事情就是觸發(fā)(調(diào)用) session下filterchain的對應(yīng)事件類型的方法逆航。
IoFilterEvent
IoFilterEvent 是IoEvent 的子類, 從名字就可以看出來渔肩, 其與IoFilter 有一定的關(guān)系因俐, 所以IoFilterEvent是由IoFilter 產(chǎn)生的事件。
而IoFilter 產(chǎn)生的事件有什么特性呢周偎?
在此插入IoFilter與IoFilterChain 的介紹女揭。
IoFilter
IoFilter 是 攔截處理事件的過濾器, 如同servlet的filter栏饮。 它可以用于很多目的:
日志記錄吧兔, 性能測量, 認證等等袍嬉。
IoFilterChain
而filterchain 即代表一串IoFilter的鏈子境蔼, 其有多個IoFilter 組成。 事實上伺通,在IoFilterChain 中箍土,封裝了一層Entry, 每個Entry中封裝了當前的IoFilter和下一個IoFilter的引用。 可以看到Entry的接口如下
interface Entry {
String getName();
IoFilter getFilter();
NextFilter getNextFilter();
void addBefore(String name, IoFilter filter);
void addAfter(String name, IoFilter filter);
void replace(IoFilter newFilter);
}
IoFilter 和NextFilter
NextFilter 顧名思義罐监, 即下一個IoFilter, 為什么需要有這么一個接口呢吴藻?
事實上, 我們可以想象弓柱, nextFilter 是用來觸發(fā) 下一個Iofilter的沟堡,其并不是IoFilter, 在IoFilter中矢空, 我們可以看到這樣的調(diào)用
void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception{
...
nextFilter.messageReceived(session,message);
}
在DefaultIoFilterChain中我們可以看到Entry的實現(xiàn)里的nextFilter 是如下實現(xiàn):
this.nextFilter = new NextFilter() {
... 省去其他方法的實現(xiàn)
public void messageReceived(IoSession session, Object message) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextMessageReceived(nextEntry, session, message);
}
};
}
可以看到該方法是獲取下一個Entry航罗,我們知道下一個entry中包含下一個IoFilter,
調(diào)用nextEntry的方法即調(diào)用entry中的Iofilter的方法:
private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
try {
IoFilter filter = entry.getFilter();
NextFilter nextFilter = entry.getNextFilter();
filter.messageReceived(nextFilter, session, message);
} catch (Exception e) {
fireExceptionCaught(e);
} catch (Error e) {
fireExceptionCaught(e);
throw e;
}
}
說完了IoFilter, IoFilterChain, 那與IoFilterEvent有什么關(guān)系呢屁药?
因為是IoFilter產(chǎn)生的事件粥血, 當觸發(fā)這個事件時, 由于鏈式的特征酿箭, 該事件將觸發(fā)當前IoFilter 以后的Filter, 所以我們看到复亏, IoFilter fire()的實現(xiàn)其實就是調(diào)用下一個filter的對應(yīng)的事件方法:
IoSession session = getSession();
NextFilter nextFilter = getNextFilter();
IoEventType type = getType();
switch (type) {
case MESSAGE_RECEIVED:
Object parameter = getParameter();
nextFilter.messageReceived(session, parameter);
...
}
也可以這樣理解, 一個事件的產(chǎn)生缭嫡, 產(chǎn)生地就是頭缔御, 事件從當前頭向鏈后傳播。
IoEvent 做的是從chain 的開頭往后傳播械巡, IoFilterEvent是由當前IoFilter產(chǎn)生往后傳播刹淌。
組裝
說完了IoFilter饶氏, 來探討一下如何將IoFilter組裝成IoFilterChain:
其實里面的結(jié)構(gòu)就是鏈表。
來看看chain中add的內(nèi)容:
add 調(diào)用register
在這里說明一下有勾, chain默認里面有2個entry疹启, 1個是head頭, 另一個是tail尾蔼卡。
public synchronized void addLast(String name, IoFilter filter) {
checkAddable(name);
register(tail.prevEntry, name, filter);
}
所以addLast (從末尾添加) 有這么幾步:
參數(shù): 末尾的前一個entry喊崖, 名字, 當前filter
1. 創(chuàng)建一個entry雇逞, 該entry的前一個entry為末尾的前一個entry荤懂,后一個entry為尾entry,
2. 修改前一個entry的后一個entry的引用,指向第一步創(chuàng)建的entry
以上其實是鏈表基本的操作塘砸。
private void register(EntryImpl prevEntry, String name, IoFilter filter) {
EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
try {
filter.onPreAdd(this, name, newEntry.getNextFilter());
} catch (Exception e) {
throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);
}
prevEntry.nextEntry.prevEntry = newEntry;
prevEntry.nextEntry = newEntry;
name2entry.put(name, newEntry);
try {
filter.onPostAdd(this, name, newEntry.getNextFilter());
} catch (Exception e) {
deregister0(newEntry);
throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);
}
}