NIO框架之MINA原始碼解析(三):底層通訊與責任鏈模式應用

chaofanwei發表於2014-09-10

NIO框架之MINA原始碼解析(一):背景


NIO框架之MINA原始碼解析(二):mina核心引擎




本文主要介紹下在mina中責任鏈模式的應用以及mina對於資料讀寫的處理。


在mina中,對資料的讀操作是在processor類裡面觸發的,收到新訊息後就觸發讀資料鏈去處理新訊息直到自己的業務邏輯程式碼(IoHandler)。


在mina中,資料的寫(write)和發(send)差別相對較大,mina中的寫訊息最終的結果只是把要寫的訊息經過寫資料鏈處理後的最終結果放在了一個快取中,並把當前session標記為可發。


資料的傳送就是傳統中我們所說的發訊息,就是把寫訊息最終處理的結果傳送到客戶端,待傳送完成後,就呼叫發資料鏈進行操作,最後再呼叫IoHandlerde 發方法。


1、觸發點

1.1、讀資料

讀操作是在Processor中的觸發的,Processor是AbstractPollingIoProcessor的內部私有類。

Processor中有一個死迴圈,迴圈呼叫Selector的select方法,若有新訊息,則進行process()。


詳見Processor程式碼。


1.2、寫資料


寫操作很簡單,是呼叫session的write方法,進行寫資料的,寫資料的最終結果儲存在一個快取佇列裡面,等待傳送,並把當前session放入flushSession佇列裡面。


1.3、 發資料


發資料其實和讀資料是差不多的,都在Processor中的觸發的,在process()完新訊息後,會呼叫flush()方法,把flushSession佇列裡面的session取出來,並把快取的訊息傳送到客戶端。

詳見Processor程式碼。


2、責任鏈模式

在mina中,責任鏈模式相關的類都定義在了org.apache.mina.core.filterchain包中,看類圖:



IoFilter介面實現代表一個具體的執行單元,是寫自定義IoFilter的介面,IoFilter有一個介面卡IoFilterAdapter,裡面什麼都沒有幹。

NextFilter介面看上去和IoFilter介面差不多,但NextFilter介面代表的是“下一個filter”,這裡的下是抽象的,因為在mina的各種鏈中,處理順序有的是從頭到尾,有的是從尾到頭,而這裡的下就代表了熟悉中的下一個filter。

Entry介面是連結中的具體物件,其封裝了IoFilter介面和NextFilter介面,代表一個實體放在鏈佇列裡面。

DefaultIoFilterChainBuilder是mina提供的一個便於使用者構造IoFilterChain的方法。



2.1、讀資料-責任鏈




2.2、寫資料-責任鏈




2.3、發資料-責任鏈




2.4 責任鏈引擎實現


這裡以讀資料-責任鏈為例,說下在mina中具體是怎麼實現這個責任鏈的執行。



engin程式碼


//class DefaultIoFilterChain

//觸發點,傳入訊息物件
 public void fireMessageReceived(Object message) {
        if (message instanceof IoBuffer) {
            session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
        }
	//從頭開始
        Entry head = this.head;
        callNextMessageReceived(head, session, message);
    }

	//這個地方是個遞迴呼叫入口,目的就是執行entry裡面的iofilter,並把當前entry的下一個nextfilter傳入
    private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
        try {
            IoFilter filter = entry.getFilter();
            NextFilter nextFilter = entry.getNextFilter();
            filter.messageReceived(nextFilter, session, message);
        } catch (Throwable e) {
            fireExceptionCaught(e);
        }
    }


iofilter程式碼,這裡面拿一個簡單的LoggingFilter來說明


//class LoggingFilter
   public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
        log(messageReceivedLevel, "RECEIVED: {}", message);
	//呼叫nextfilter的receive方法,執行下一個filter
	//也可以不呼叫,直接返回
        nextFilter.messageReceived(session, message);

	//當然也可以在這裡加一些處理後的業務邏輯。
    }

nextfilter程式碼


private class EntryImpl implements Entry {
        private EntryImpl prevEntry;

        private EntryImpl nextEntry;

        private final String name;

        private IoFilter filter;

        private final NextFilter nextFilter;

        private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) {
            if (filter == null) {
                throw new IllegalArgumentException("filter");
            }
            if (name == null) {
                throw new IllegalArgumentException("name");
            }

            this.prevEntry = prevEntry;
            this.nextEntry = nextEntry;
            this.name = name;
            this.filter = filter;
            this.nextFilter = new NextFilter() {
              
                public void messageReceived(IoSession session, Object message) {
                    Entry nextEntry = EntryImpl.this.nextEntry;
		    //把nextEntry指向相應的entry,繼續進入迴圈體,注意這裡的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;
		    //把nextEntry指向相應的entry,繼續進入迴圈體,注意這裡的EntryImpl.this.prevEntry,即從尾到頭
                    callPreviousFilterWrite(nextEntry, session, writeRequest);
                }
          
            };
        }

        public String getName() {
            return name;
        }

        public IoFilter getFilter() {
            return filter;
        }       
    }





相關文章