mina 源码解析(1)

mina是一款网络应用框架, 它是基于java nio 的 通讯框架, 提供抽象的事件驱动异步的api。

mina 基本架构:

0_1331696777kKre.gif

大致上分为三层IoSerivce, Filter, Handler

首先我们来看一下Filter

事件

前面说过, mina 是基于事件驱动的, 所以我们先来看一下mina定义了那些事件:
IoEventType 类中定义了如下枚举变量:

public enum IoEventType {
    SESSION_CREATED,     session 创建
    SESSION_OPENED,      session 开启
    SESSION_CLOSED,      session 关闭
    MESSAGE_RECEIVED,    消息收到
    MESSAGE_SENT,        消息发送
    SESSION_IDLE,        session 闲置
    EXCEPTION_CAUGHT,    发生异常异常捕获
    WRITE,               写事件 out
    CLOSE,               关闭事件
}

这些事件对于用户使用者来说无需关心。
以上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 实现了Runnable,也就是说这个对象会交给多线程去执行run方法。
在run方法中我们看到执行的是fire(), 也就是具体的任务了。

下面来看一下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;
    .... 
}

其实做的事情就是触发(调用) session下filterchain的对应事件类型的方法。

IoFilterEvent

IoFilterEvent 是IoEvent 的子类, 从名字就可以看出来, 其与IoFilter 有一定的关系, 所以IoFilterEvent是由IoFilter 产生的事件。
而IoFilter 产生的事件有什么特性呢?

在此插入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 是用来触发 下一个Iofilter的,其并不是IoFilter, 在IoFilter中, 我们可以看到这样的调用

void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception{
    ...
    nextFilter.messageReceived(session,message);
}

在DefaultIoFilterChain中我们可以看到Entry的实现里的nextFilter 是如下实现:
 this.nextFilter = new NextFilter() {
            ... 省去其他方法的实现
                public void messageReceived(IoSession session, Object message) {
                    Entry nextEntry = EntryImpl.this.nextEntry;
                    callNextMessageReceived(nextEntry, session, message);
                }

            };
        }
可以看到该方法是获取下一个Entry,我们知道下一个entry中包含下一个IoFilter,  
调用nextEntry的方法即调用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有什么关系呢?
因为是IoFilter产生的事件, 当触发这个事件时, 由于链式的特征, 该事件将触发当前IoFilter 以后的Filter, 所以我们看到, IoFilter fire()的实现其实就是调用下一个filter的对应的事件方法:

IoSession session = getSession();
NextFilter nextFilter = getNextFilter();
IoEventType type = getType();
switch (type) {
case MESSAGE_RECEIVED:
    Object parameter = getParameter();
    nextFilter.messageReceived(session, parameter);
... 
    
}

也可以这样理解, 一个事件的产生, 产生地就是头, 事件从当前头向链后传播。
IoEvent 做的是从chain 的开头往后传播, IoFilterEvent是由当前IoFilter产生往后传播。

组装

说完了IoFilter, 来探讨一下如何将IoFilter组装成IoFilterChain:

其实里面的结构就是链表。
来看看chain中add的内容:

add 调用register
在这里说明一下, chain默认里面有2个entry, 1个是head头, 另一个是tail尾。
public synchronized void addLast(String name, IoFilter filter) {
    checkAddable(name);
    register(tail.prevEntry, name, filter);
}
所以addLast (从末尾添加) 有这么几步:
参数: 末尾的前一个entry, 名字, 当前filter
1. 创建一个entry, 该entry的前一个entry为末尾的前一个entry,后一个entry为尾entry,
2. 修改前一个entry的后一个entry的引用,指向第一步创建的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);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容

  • 用到的组件 1、通过CocoaPods安装 2、第三方类库安装 3、第三方服务 友盟社会化分享组件 友盟用户反馈 ...
    SunnyLeong阅读 14,610评论 1 180
  • 本文包括:1、Filter简介2、Filter是如何实现拦截的?3、Filter开发入门4、Filter的生命周期...
    廖少少阅读 7,266评论 3 56
  • webstrom11注册码网址 vue.js相关组件,比如UI组件什么 jsonserver地址
    南蓝NL阅读 157评论 0 0
  • 今天,有满满的一天,一天都是调整啊~ 人生寂寞如雪,在这个夏天的日子,我过着冬天的生活,然后猛然穿越到夏的国度~ ...
    蜜呢阅读 125评论 0 0
  • 一千个读者就有一千个哈姆雷特,而我的英雄联盟之路,独一无二。 初识英雄联盟是在2012年,福州西湖之畔的某网吧,我...
    甩尾鱼阅读 414评论 13 5