前面提到了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決定。