轉:Mina2.0架構源碼剖析(六)

來源:互聯網
上載者:User

上文的內容還有一些沒有結尾,這篇補上。在ExpiringMap類中,使用了一個私人內部類ExpiringObject來表示待檢查逾時的對象,它包括三個域,鍵,值,上次訪問時間,以及用於上次訪問時間這個域的讀寫鎖:

        private K key;
        private V value;
        private long lastAccessTime;
        private final ReadWriteLock lastAccessTimeLock = new ReentrantReadWriteLock();

而ExpiringMap中包括了下述幾個變數:

  private final ConcurrentHashMap<K, ExpiringObject> delegate;//逾時代理集合,儲存待檢查對象
    private final CopyOnWriteArrayList<ExpirationListener<V>> expirationListeners;//逾時監聽者
    private final Expirer expirer;//逾時檢查線程

現在再來看看IoSession的一個抽象實作類別AbstractIoSession。這是它的幾個重要的成員變數:

    private IoSessionAttributeMap attributes;//會話屬性對應圖
    private WriteRequestQueue writeRequestQueue;//寫請求隊列
    private WriteRequest currentWriteRequest;//當前寫請求

     當要結束當前會話時,會發送一個一個寫請求CLOSE_REQUEST。而closeFuture這個CloseFuture會在串連關閉時狀態被設定為”closed”,它的監聽器是SCHEDULED_COUNTER_RESETTER。

close和closeOnFlush都是非同步關閉操作,區別是前者立即關閉串連,而後者是在寫請求隊列中放入一個CLOSE_REQUEST,並將其即時重新整理出去,若要真正等待關閉完成,需要調用方在返回的CloseFuture等待

public final CloseFuture close() {
        synchronized (lock) {
            if (isClosing()) {
                return closeFuture;
            } else {
                closing = true;
            }
        }
        getFilterChain().fireFilterClose();//fire出關閉事件
        return closeFuture;
    }

 

    public final CloseFuture closeOnFlush() {
        getWriteRequestQueue().offer(this, CLOSE_REQUEST);
        getProcessor().flush(this);
        return closeFuture;
    }

     下面來看看讀資料的過程:

public final CloseFuture close() {
        synchronized (lock) {
            if (isClosing()) {
                return closeFuture;
            } else {
                closing = true;
            }
        }
        getFilterChain().fireFilterClose();//fire出關閉事件
        return closeFuture;
    }

 

    public final CloseFuture closeOnFlush() {
        getWriteRequestQueue().offer(this, CLOSE_REQUEST);
        getProcessor().flush(this);
        return closeFuture;
    }

    private Queue<ReadFuture> getReadyReadFutures() {//返回可被讀資料隊列
        Queue<ReadFuture> readyReadFutures =
            (Queue<ReadFuture>) getAttribute(READY_READ_FUTURES_KEY);//從會話映射表中取出可被讀資料隊列
        if (readyReadFutures == null) {//第一次讀資料
            readyReadFutures = new CircularQueue<ReadFuture>();//構造一個新讀資料隊列
            Queue<ReadFuture> oldReadyReadFutures =
                (Queue<ReadFuture>) setAttributeIfAbsent(
                        READY_READ_FUTURES_KEY, readyReadFutures);
            if (oldReadyReadFutures != null) {
                readyReadFutures = oldReadyReadFutures;
            }
        }
        return readyReadFutures;
    }

    public final ReadFuture read() {//讀資料
        if (!getConfig().isUseReadOperation()) {//會話配置不允許讀資料(這是預設情況)
            throw new IllegalStateException("useReadOperation is not enabled.");
        }
        Queue<ReadFuture> readyReadFutures = getReadyReadFutures();//擷取已經可被讀資料隊列
        ReadFuture future;
        synchronized (readyReadFutures) {//鎖住讀資料隊列
            future = readyReadFutures.poll();//取隊頭資料
            if (future != null) {
                if (future.isClosed()) {//關聯的會話已經關閉了,讓讀者知道此情況
                    readyReadFutures.offer(future);
                }
            } else {
                future = new DefaultReadFuture(this);
                getWaitingReadFutures().offer(future); //將此資料插入等待被讀取資料的隊列,這個代碼和上面的getReadyReadFutures類似,只是索引值不同而已

            }
        }
        return future;
    }

     再來看寫資料到指定遠端地址的過程,可以寫三種類型資料:IoBuffer,整個檔案或檔案的部分地區,這會通過傳遞寫請求給過濾器鏈條來完成資料向目的遠端的傳輸。

    public final WriteFuture write(Object message, SocketAddress remoteAddress) {
        FileChannel openedFileChannel = null;
        try 
        {
            if (message instanceof IoBuffer&& !((IoBuffer) message).hasRemaining()) 
            {// 空訊息
                throw new IllegalArgumentException(
                "message is empty. Forgot to call flip()?");
            } 
            else if (message instanceof FileChannel) 
            {//要發送的是檔案的某一地區
                FileChannel fileChannel = (FileChannel) message;
                message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
            }
            else if (message instanceof File) 
            {//要發送的是檔案,開啟檔案通道
                File file = (File) message;
                openedFileChannel = new FileInputStream(file).getChannel();
                message = new DefaultFileRegion(openedFileChannel, 0, openedFileChannel.size());
            }
        } 
        catch (IOException e) 
        {
            ExceptionMonitor.getInstance().exceptionCaught(e);
            return DefaultWriteFuture.newNotWrittenFuture(this, e);
        }
        WriteFuture future = new DefaultWriteFuture(this); 
        getFilterChain().fireFilterWrite(
                new DefaultWriteRequest(message, future, remoteAddress)); //構造寫請求,通過過濾器鏈發送出去,寫請求中指明了要發送的訊息,目的地址,以及返回的結果
 
//如果開啟了一個檔案通道(發送的檔案的部分地區或全部),就必須在寫請求完成時關閉檔案通道
        if (openedFileChannel != null) {
            final FileChannel finalChannel = openedFileChannel;
            future.addListener(new IoFutureListener<WriteFuture>() {
                public void operationComplete(WriteFuture future) {
                    try {
                        finalChannel.close();//關閉檔案通道
                    } catch (IOException e) {
                        ExceptionMonitor.getInstance().exceptionCaught(e);
                    }
                }
            });
        }
        return future;//寫請求成功完成
    }

     最後,來看看一個WriteRequestQueue的實現,唯一加入的一個功能就是若在隊頭髮現是請求關閉,則會去關閉會話。

 private class CloseRequestAwareWriteRequestQueue implements WriteRequestQueue {
        private final WriteRequestQueue q;//內部實際的寫請求隊列
        public CloseRequestAwareWriteRequestQueue(WriteRequestQueue q) {
            this.q = q;
        }
        public synchronized WriteRequest poll(IoSession session) {
            WriteRequest answer = q.poll(session);
            if (answer == CLOSE_REQUEST) {
                AbstractIoSession.this.close();
                dispose(session);
                answer = null;
            }
            return answer;
        }
        public void offer(IoSession session, WriteRequest e) {
            q.offer(session, e);
        }
        public boolean isEmpty(IoSession session) {
            return q.isEmpty(session);
        }
        public void clear(IoSession session) {
            q.clear(session);
        }
        public void dispose(IoSession session) {
            q.dispose(session);
        }
    }

 

作者:phinecos(洞庭散人)
出處:http://phinecos.cnblogs.com/
本文著作權歸作者和部落格園共有,歡迎轉載,但請保留此段聲明,並在文章頁面明顯位置給出原文串連。

作者:洞庭散人

出處:http://phinecos.cnblogs.com/    

本部落格遵從Creative Commons Attribution 3.0 License,若用於非商業目的,您可以自由轉載,但請保留原作者資訊和文章連結URL。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.