Apache Mina Filter

Mina中的過濾器處於IoService與IoHandler之間,用於過濾每一個I/O事件。本文分析Mina中的過濾器是怎麼串起來的?

前面提到了IoFilter,FilterChain等接口和類,在分析過濾器鏈怎麼串起來之前,有必要看一下這些接口和類之間的關係。


如上圖所示:

FilterChain是由一個個Entry串起來的,EntryImpl是Entry的實現;

從EntryImpl中可以獲取到Filter與NextFilter,NextFilter相當於那根線(指針);

有兩個特殊的Entry,裏面的Filter分別是HeadFilter和TailFilter,我們添加的Filter都處於這兩個Filter之間;

每做完一個Entry,NextFilter會回到FilterChain處理下一個Entry(處理順序如下圖所示)。


由上圖可知:

(1)當消息到來時,觸發過濾器鏈的fireXXX事件(這一步一般在processor裏面觸發);

(2)從過濾器鏈獲取上頭結點Entry,從頭結點Entry中取出filter和nextFilter;

(3)Filter處理後,交由nextFilter處理,nextFilter並不是一個真正的Filter,它決定這個過濾器鏈的走向,在這裏它是返回到過濾器鏈;

(4)過濾器鏈通過nextFilter指針得到下一個entry,重複執行(2)、(3),直到每個Entry都處理完。

這裏拋出兩個問題:

1、如何保證新加入的過濾器在HeadFilter與TailFilter之間?

2、nextFilter一定是從左向右的順序嗎?

3、TailFilter調用了IoHandler嗎?

對於第一個問題,答案在EntryImpl的構造方法裏面

// EntryImpl構造方法
private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) {
		......
    this.prevEntry = prevEntry;
    this.nextEntry = nextEntry;
    this.name = name;
    this.filter = filter;
    this.nextFilter = new NextFilter() {
        ......
    };
}

//FilterChain構造方法
public DefaultIoFilterChain(AbstractIoSession session) {
    if (session == null) {
        throw new IllegalArgumentException("session");
    }

    this.session = session;
    head = new EntryImpl(null, null, "head", new HeadFilter());
    tail = new EntryImpl(head, null, "tail", new TailFilter());
    head.nextEntry = tail;
}
在FilterChain構造方法裏面初始化了兩個Entry:


我們一般調用IoFilterChain的如下方法添加過濾器

void addFirst(String name, IoFilter filter);
void addLast(String name, IoFilter filter);
void addBefore(String baseName, String name, IoFilter filter);
void addAfter(String baseName, String name, IoFilter filter);
這裏以addLast爲例,先看看addLast方法的實現

public synchronized void addFirst(String name, IoFilter filter) {
	checkAddable(name);
	register(head, name, filter);
}

private void register(EntryImpl prevEntry, String name, IoFilter filter) {
	EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
	......
	prevEntry.nextEntry.prevEntry = newEntry;
	prevEntry.nextEntry = newEntry;
	name2entry.put(name, newEntry);
	......
}
從代碼一目瞭然,這就是一個簡單的鏈表操作,在這裏第一個問題回答完畢。

對於第二個問題答案是否定的。從IoFilter接口可以看出,一共處理以下幾種事件:

sessionCreated
sessionOpened
sessionClosed
sessionIdle
exceptionCaught
messageReceived
messageSent
filterClose
filterWrite
前面FilterChain的構造方法中,省略了NextFilter的實現,這裏補上

 this.nextFilter = new NextFilter() {
      public void sessionCreated(IoSession session) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextSessionCreated(nextEntry, session);
      }

      public void sessionOpened(IoSession session) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextSessionOpened(nextEntry, session);
      }

      public void sessionClosed(IoSession session) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextSessionClosed(nextEntry, session);
      }

      public void sessionIdle(IoSession session, IdleStatus status) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextSessionIdle(nextEntry, session, status);
      }

      public void exceptionCaught(IoSession session, Throwable cause) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextExceptionCaught(nextEntry, session, cause);
      }

      public void messageReceived(IoSession session, Object message) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextMessageReceived(nextEntry, session, message);
      }

      public void messageSent(IoSession session, WriteRequest writeRequest) {
          Entry nextEntry = EntryImpl.this.nextEntry;
          callNextMessageSent(nextEntry, session, writeRequest);
      }

      public void filterWrite(IoSession session, WriteRequest writeRequest) {
          Entry nextEntry = EntryImpl.this.prevEntry;
          callPreviousFilterWrite(nextEntry, session, writeRequest);
      }

      public void filterClose(IoSession session) {
          Entry nextEntry = EntryImpl.this.prevEntry;
          callPreviousFilterClose(nextEntry, session);
      }
}

可以看出filterWrite與filterClose是反向的,其他都是正向的。

對於第三個問題,直接看TailFilter的代碼即可:

public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
    AbstractIoSession s = (AbstractIoSession) session;
    if (!(message instanceof IoBuffer)) {
        s.increaseReadMessages(System.currentTimeMillis());
    } else if (!((IoBuffer) message).hasRemaining()) {
        s.increaseReadMessages(System.currentTimeMillis());
    }

    try {
        session.getHandler().messageReceived(s, message);
    } finally {
        if (s.getConfig().isUseReadOperation()) {
            s.offerReadFuture(message);
        }
    }
}
確實調用了handler來處理真正的請求。

總結一下:FilterChain是由Entry組成一個鏈表,HeadFilter與TailFilter所在Entry分別是鏈表的首尾,HeadFilter與processor相連,TailFilter與handler相連,添加Filter的操作實際上是普通的鏈表插入操作。FilterChain可以觸發多種事件,每種事件到來時Filter的順序是正序還是倒序由nextFilter決定。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章