《Apache MINA 2.0 使用者指南》第五章:過濾器
- LoggingFilter 記錄所有事件和請求
- ProtocolCodecFilter 將一個連入的 ByteBuffer 轉化為訊息 POJO,反之亦然
- CompressionFilter 壓縮所有資料
- SSLFilter 新增 SSL - TLS - StartTLS 支援
- 不止如此!
現有的過濾器
我們已經有很多寫好的過濾器了。下表列出了所有現有的過濾器,並在他們的用途方面進行簡要說明。
選擇事件重寫
你可以對 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 有所不同。同時也參考一下 CompressionFilter 和 RequestResponseFilter。
過濾 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 塊了
原文連結: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環境的鏡像,但直接使用