mina 源碼解析(1)

mina是一款網(wǎng)絡(luò)應(yīng)用框架, 它是基于java nio 的 通訊框架, 提供抽象的事件驅(qū)動異步的api掀虎。

mina 基本架構(gòu):

0_1331696777kKre.gif

大致上分為三層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);
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末节仿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掉蔬,更是在濱河造成了極大的恐慌廊宪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件女轿,死亡現(xiàn)場離奇詭異箭启,居然都是意外死亡,警方通過查閱死者的電腦和手機蛉迹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門傅寡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人北救,你說我怎么就攤上這事号枕≌鸺担” “怎么了兰迫?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵漾唉,是天一觀的道長。 經(jīng)常有香客問我膛壹,道長,這世上最難降的妖魔是什么唉堪? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任模聋,我火速辦了婚禮,結(jié)果婚禮上唠亚,老公的妹妹穿的比我還像新娘链方。我一直安慰自己,他們只是感情好灶搜,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布祟蚀。 她就那樣靜靜地躺著工窍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪前酿。 梳的紋絲不亂的頭發(fā)上患雏,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機與錄音罢维,去河邊找鬼淹仑。 笑死,一個胖子當著我的面吹牛肺孵,可吹牛的內(nèi)容都是我干的匀借。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼平窘,長吁一口氣:“原來是場噩夢啊……” “哼吓肋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瑰艘,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蓬坡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后磅叛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屑咳,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年弊琴,在試婚紗的時候發(fā)現(xiàn)自己被綠了兆龙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡敲董,死狀恐怖紫皇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腋寨,我是刑警寧澤聪铺,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站萄窜,受9級特大地震影響铃剔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜查刻,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一键兜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧穗泵,春花似錦普气、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仔沿,卻和暖如春坐桩,著一層夾襖步出監(jiān)牢的瞬間于未,已是汗流浹背撕攒。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工抖坪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闷叉。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像握侧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子品擎,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 用到的組件 1、通過CocoaPods安裝 2萄传、第三方類庫安裝 3甚颂、第三方服務(wù) 友盟社會化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 14,629評論 1 180
  • 本文包括:1秀菱、Filter簡介2、Filter是如何實現(xiàn)攔截的衍菱?3赶么、Filter開發(fā)入門4脊串、Filter的生命周期...
    廖少少閱讀 7,282評論 3 56
  • webstrom11注冊碼網(wǎng)址 vue.js相關(guān)組件,比如UI組件什么 jsonserver地址
    南藍NL閱讀 160評論 0 0
  • 今天洪规,有滿滿的一天印屁,一天都是調(diào)整啊~ 人生寂寞如雪,在這個夏天的日子斩例,我過著冬天的生活,然后猛然穿越到夏的國度~ ...
    蜜呢閱讀 127評論 0 0
  • 一千個讀者就有一千個哈姆雷特从橘,而我的英雄聯(lián)盟之路念赶,獨一無二础钠。 初識英雄聯(lián)盟是在2012年,福州西湖之畔的某網(wǎng)吧叉谜,我...
    甩尾魚閱讀 422評論 13 5