1. 程式人生 > >《Apache MINA 2.0 使用者指南》第五章:過濾器

《Apache MINA 2.0 使用者指南》第五章:過濾器

        IoFilter 扮演著很重要角色,它是 MINA 的核心結構之一。它過濾 IoService 和 IoHandler 之間的所有 I/O 事件和請求。如果你有網路應用程式設計的經驗,你完全可以把它當成 Servlet 過濾器的表兄弟。許多開箱即用的過濾器通過使用類似以下的開箱即用過濾器簡化橫切注入用來提升網路應用的開發速度:
  • LoggingFilter 記錄所有事件和請求
  • ProtocolCodecFilter 將一個連入的 ByteBuffer 轉化為訊息 POJO,反之亦然
  • CompressionFilter 壓縮所有資料
  • SSLFilter 新增 SSL - TLS - StartTLS 支援
  • 不止如此!
        本文我們將瞭解如何為一個真實案例實現一個 IoFilter。通常實現一個 IoFilter 是很簡單的,但你也需要 MINA 的內部細節。本文將對這些相關內部細節進行解釋。
        現有的過濾器
        我們已經有很多寫好的過濾器了。下表列出了所有現有的過濾器,並在他們的用途方面進行簡要說明。



        選擇事件重寫

        你可以對 IoAdapter 重寫以取代直接實現 IoFilter 的做法。除非重寫,否則所有接收到的事件將被直接轉發給下一個過濾器。
public class MyFilter extends IoFilterAdapter {
    @Override
    public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
        // Some logic here...
        nextFilter.sessionOpened(session);
        // Some other logic here...
    }
}

        轉換寫請求
        如果你要通過 IoSession.write() 對一個連入的寫請求進行轉換,事情可能會變得相當棘手。例如,假設你的過濾器在一個 HighLevelMessage 物件呼叫 IoSession.write() 時將 HighLevelMessage 轉換為 LowLevelMessage。你可以在你的過濾器的 filterWrite() 方法裡新增適當的轉換程式碼並認為一切就這樣了。但是你也需要注意 messageSent 事件,因為一個 IoHandler 或者任何之後的過濾器會期望 messageSent() 方法以 HighLevelMessage 作為引數呼叫,因為讓呼叫者在寫 HighLevelMessage 的時候被通知到 HighLevelMessage 已傳送是不合理的。因此,如果你的過濾器負責轉換時你最好同時實現 filterWrite() 和 messageSent()。
        另外還要注意的是,你仍舊需要實現類似的機制,即使輸入物件和輸出物件的型別是一樣的,因為 IoSession.write() 的呼叫者期望它的 messageSent() 處理器方法有一個具體物件。
        假定你在實現一個將字串轉換為字元陣列的過濾器。你的過濾器的 filterWrite() 將會類似於:
public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest request) {
    nextFilter.filterWrite(
        session, new DefaultWriteRequest(
                ((String) request.getMessage()).toCharArray(), request.getFuture(), request.getDestination()));
}

        現在我們需要在 messageSent() 中做相反的事情:
public void messageSent(NextFilter nextFilter, IoSession session, Object message) {
    nextFilter.messageSent(session, new String((char[]) message));
}

        字串到位元組快取的轉換怎麼樣?這樣我們會更加高效,我們不在需要重建原始訊息 (字串)。但是,這比前面的例子複雜:
public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest request) {
    String m = (String) request.getMessage();
    ByteBuffer newBuffer = new MyByteBuffer(m, ByteBuffer.wrap(m.getBytes());

    nextFilter.filterWrite(
            session, new WriteRequest(newBuffer, request.getFuture(), request.getDestination()));
}

public void messageSent(NextFilter nextFilter, IoSession session, Object message) {
    if (message instanceof MyByteBuffer) {
        nextFilter.messageSent(session, ((MyByteBuffer) message).originalValue);
    } else {
        nextFilter.messageSent(session, message);
    }
}

private static class MyByteBuffer extends ByteBufferProxy {
    private final Object originalValue;
    private MyByteBuffer(Object originalValue, ByteBuffer encodedValue) {
        super(encodedValue);
        this.originalValue = originalValue;
    }
}

        如果你使用的是 MINA 2.0,這將跟 1.0 和 1.1 有所不同。同時也參考一下 CompressionFilterRequestResponseFilter
        過濾 sessionCreated 事件時須謹慎
        sessionCreated 是一個特殊事件,它必須在 I/O 處理程式中執行 (參考 執行緒模型的配置)。決不允許將 sessionCreated 事件轉發給其他執行緒。
public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
    // ...
    nextFilter.sessionCreated(session);
}

// DON'T DO THIS!
public void sessionCreated(final NextFilter nextFilter, final IoSession session) throws Exception {
    Executor executor = ...;
    executor.execute(new Runnable() {
        nextFilter.sessionCreated(session);
        });
    }

        提防空快取!
        在一些案例中 MINA 使用了一個空的緩衝區作為一個內部訊號。空快取有時會成為一個問題,因為它可能會造成各種各樣的異常,比如 IndexOutOfBoundsException。這裡我們介紹如何避免類似於這種難以預料的情況。
        ProtocolCodecFilter 使用了一個空快取 (比如 buf.hasRemaining() = 0) 來標記訊息的結束部分。如果你的過濾器放在 ProtocolCodecFilter 之前,如果你的過濾器實現在快取為空時能丟擲一個異常的話,請確認你的過濾器將空快取轉發給了下一個過濾器:
public void messageSent(NextFilter nextFilter, IoSession session, Object message) {
    if (message instanceof ByteBuffer && !((ByteBuffer) message).hasRemaining()) {
        nextFilter.messageSent(nextFilter, session, message);
        return;
    }
    ...
}

public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest request) {
    Object message = request.getMessage();
    if (message instanceof ByteBuffer && !((ByteBuffer) message).hasRemaining()) {
        nextFilter.filterWrite(nextFilter, session, request);
        return;
    }
    ...
}

        這樣的話,我們是否總是要為每個過濾器插入 if 塊?幸運的是,不需要。這是處理空快取的黃金法則:
  • 如果你的過濾器及時在快取為空時也能正常工作,你就完全不需要新增 if 塊了
  • 如果你的過濾器放在 ProtocolCodecFilter 之後,你也不需要新增 if 塊
  • 除此之外的話你就需要 if 塊了
        如果你需要加 if 塊,記著你不總是需要遵循上面例子所講的。你可以在任何地方檢查快取是否為空,只要你的過濾器不會丟擲異常。譯者注:之所以如此這般謹慎處理,是因為一旦在過濾器中丟擲異常,當前執行緒即消亡,負責該項業務處理的邏輯將會出席問題,因為後續過濾器無法對其進行繼續處理。
原文連結:http://mina.apache.org/mina-project/userguide/ch5-filters/ch5-filters.html

相關推薦

Apache MINA 2.0 使用者指南過濾器

        IoFilter 扮演著很重要角色,它是 MINA 的核心結構之一。它過濾 IoService 和 IoHandler 之間的所有 I/O 事件和請求。如果你有網路應用程式設計的經驗,你完全可以把它當成 Servlet 過濾器的表兄弟。許多開箱即用的過濾器通過

Apache MINA 2.0 使用者指南十二日誌過濾器

        背景Apache MINA 體系允許基於 MINA 的應用的開發者使用他們自己的日誌系統。SLF4JMINA 使用了簡單日誌門面 (Simple Logging Facade for Java,SLF4J)。你可以在這裡找到 SLF4J 的資訊。這個日誌工具允

Apache MINA 2.0 使用者指南會話

        會話處於 MINA 的核心位置:每當一個客戶端連線到伺服器,一個新的會話會被建立,並會在客戶端關掉連線前一直儲存在記憶體中。        會話用於儲存連線的持久資訊,以及在請求處理過程中、會話的生命週期中伺服器可能需要用到的任何資訊。        會話的狀

Apache Mina 2.0.x 入門

Apache Mina ,一個高效能 Java 非同步併發網路通訊框架。利用 Mina 可以高效地完成以下任務: TCP/IP 和 UDP/IP 通訊 串列埠通訊 VM 間的管道通訊 SSL/TLS JXM 整合 IoC 容器整合(

Apache Spark 2.0三種API的傳說RDD、DataFrame和Dataset

sensor json數據 query 答案 內存 table 引擎 library spark Apache Spark吸引廣大社區開發者的一個重要原因是:Apache Spark提供極其簡單、易用的APIs,支持跨多種語言(比如:Scala、Java、Python和R

C#本質論6.0

得到 結束 管理 多個實例 局部變量 理解 管理器 靜態方法 修改 面向對象編程 封裝: 封裝的目的是隱藏細節。在必要的時候,細節仍然可以訪問,但通過巧妙的封裝細節,大的程序變得更容易理解,數據不會因為不慎而被修改,代碼也變得更容易維護。 繼承: 繼承允許在這些相似但又不同

祕籍--- 閉包

閉包概念:一個一個函式在建立時允許自身函式訪問自身函式之外的變數時所建立的作用域。即是在小的作用域內允許訪問大作用域內的資訊。 { XXX //XXX能訪問到YYY中 { YYY //YYY能夠訪問到XXX } } 這就是閉包 閉包的幾個性質: 1,內部函式的引數是包含在閉包中的。 2,

Android程式設計權威指南學習

第五章—第二個activity 5.1.1 建立新的 activity 建立新的activity至少涉及三個檔案: Java類、 XML佈局和應用的manifest檔案。這三個文 件關聯密切,搞錯了就是災難。因此,強烈建議使用Android Studio的新建a

《第一行程式碼》 全域性大喇叭 筆記(基於Android8.0

由於Android8.0對廣播機制做了很大的調整理,導致《第一行程式碼》中很多例項無法正常執行,因此我結合書本,自行整理了一下。 廣播需要接收器和傳送器。系統的動作都會發送一條廣播,例如電量的變化,系

05.ThreeJs開發指南--幾何體

第五章 學習使用幾何體 二維幾何體: 一、PlaneGeometry:平面 var plane = new THREE.PlaneGeometry(width,height,widthSegments,heightSegments); width:

Kali Linux 無線滲透測試入門指南 攻擊 Web 設施

第五章 攻擊 Web 設施 作者:Vivek Ramachandran, Cameron Buchanan 譯者:飛龍 簡介 故上兵伐謀 – 孫子,《孫子兵法》 這一章中,我們會攻擊 WLAN 設施的核

SpringBoot 2.X課程學習 | yml語法讓配置檔案更加簡潔易讀

簡介       YAML 是一種簡潔的非標記語言(YAML Ain’t Markup Lang

讀構建之法 團隊和流程

min 這樣的 程序員 希望 成員 eat 貢獻 核心 不能 團隊有一致的集體目標,團隊要一起完成這目標。一個團隊的成員不一定要同時工作,例如接力賽跑。 團隊成員有各自的分工,互相依賴合作,共同完成任務。 軟件團隊有各種形式,適用於不同的人員和需求。基於直覺形成的團隊模式未

面向對象1

沒有 值傳遞 默認 封裝性 軟件開發 大型項目 語句 開發思想 實現 面向對象和面向過程的區別 兩者都是軟件開發思想,先有面向過程,後有面向對象。在大型項目中,針對面向過程的不足推出了面向對象開發思想。區別1. 編程思路不同: 面向過程以實現功能的函數開發為主,而面向對象要

條件、循環和其它語句

tde pop 空格 fin program 比較 isspace 才有 刪除 5.1 print和import的更多使用方式 5.1.1 使用逗號輸出 print ‘Age‘,42 print 1,2,3 如果要同時輸出文本和變量值,又不希望使用字符串格式化的話

循環結構(一)

如何 如何使用 滿足 為什麽 發現 每日 生活 打印機 結構 第五章:循環結構(一) 1.什麽是循環結構 在日常生活中,會有很多需要反復執行的事情,比如:每一年的 4個季節,每一周的7天,每日的3餐,打印機每份文檔打印50 份,一圈跑道400米跑3圈,都是在反復執行的。 2

Python 之 RabbitMQ消息持久化

rabbitmq#測試RabbitMQ消息永久化 #1. 分隊列永久化和信息永久化 #2. 意思為當服務重啟後,隊列和消息還存在,可供客戶端接受 #3. 在服務器查看消息隊列命令./rabbitmqctl list_queues #send 端 import pika credentials = pik

Python 之 RabbitMQ 基本示例

rabbitmq#send 端import pikacredentials = pika.PlainCredentials(‘root‘, ‘Password1‘)connection = pika.BlockingConnection(pika.ConnectionParameters(‘10.3.151.

需求以及概念設計

反饋 實現 價值 用戶反饋 軟件 設計 customer 關於 互聯網 前言 今天的這一回是關於產品誕生的部分,既廣義的從0到1。 發現需求 這裏將發現需求的方法分成兩大類:用戶研究與產品研究。 1.用戶研究建立用戶畫像(Persona) 用戶畫像是通過對目標群體真

Docker | 構建自定義鏡像

openjdk -a http get ble 遠程 準備 linux命令 sna 前言 上一章節,主要是介紹了下Dockerfile的一些常用命令的說明。我們知道,利用Dockerfile可以構建一個新的鏡像,比如運行Java環境,就需要一個JDK環境的鏡像,但直接使用