Mina文檔 05-過濾器
IoFilter是MINA核心構造之一,起著非常重要的作用。它過濾IoService和IoHandler之間的所有I / O事件和請求。如果您有Web應用程序編程經驗,可以放心地認為它是Servlet過濾器的表兄弟。提供了許多開箱即用的過濾器,通過使用開箱即用的過濾器簡化典型的橫切關註點來加速網絡應用程序開發速度,例如:
1.LoggingFilter記錄所有事件和請求。
2.ProtocolCodecFilter將傳入的ByteBuffer轉換為消息POJO,反之亦然。
3.CompressionFilter壓縮所有數據。
4.SSLFilter添加SSL - TLS - StartTLS支持。
5.還有很多!
在本教程中,我們將介紹如何為現實世界的用例實現IoFilter。一般來說,實現IoFilter很容易,但您可能還需要了解MINA內部的細節。這裏將解釋任何相關的內部屬性。
1.已實現的過濾器
2.有選擇地覆蓋事件
3.轉換寫請求
4.過濾sessionCreated事件時要小心
5.註意空緩沖!
已實現的過濾器
我們已經編寫了許多過濾器。下表列出了所有現有過濾器,並簡要說明了其用法。
過濾器 |
類 |
描述 |
Blacklist |
BlacklistFilter |
阻止列入黑名單的遠程地址的連接 |
Buffered Write |
BufferedWriteFilter |
像BufferedOutputStream一樣緩存傳出請求 |
Compression |
CompressionFilter |
|
ConnectionThrottle |
ConnectionThrottleFilter |
|
ErrorGenerating |
ErrorGeneratingFilter |
|
Executor |
ExecutorFilter |
|
FileRegionWrite |
FileRegionWriteFilter |
|
KeepAlive |
KeepAliveFilter |
|
Logging |
LoggingFilter |
記錄事件消息,如MessageReceived,MessageSent,SessionOpened,.... |
MDC Injection |
MdcInjectionFilter |
將關鍵IoSession屬性註入MDC |
Noop |
NoopFilter |
一個什麽都不做的過濾器。對測試有用。 |
Profiler |
ProfilerTimerFilter |
配置文件事件消息,如MessageReceived,MessageSent,SessionOpened,... |
ProtocolCodec |
ProtocolCodecFilter |
負責編碼和解碼消息的過濾器 |
Proxy |
ProxyFilter |
|
Reference counting |
ReferenceCountingFilter |
跟蹤此過濾器的使用次數 |
RequestResponse |
RequestResponseFilter |
|
SessionAttributeInitializing |
SessionAttributeInitializingFilter |
|
StreamWrite |
StreamWriteFilter |
|
SslFilter |
SslFilter |
|
WriteRequest |
WriteRequestFilter |
|
有選擇地覆蓋事件
您可以擴展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或您旁邊的任何過濾器都希望使用HighLevelMessage作為參數調用messageSent()方法,因為調用者收到LowLevelMessage的通知是不合理的。當調用者實際編寫HighLevelMessage時發送。因此,如果過濾器執行轉換,則必須同時實現filterWrite()和messageSent()。
還請註意,即使輸入對象和輸出對象的類型相同(例如CompressionFilter),您仍然需要實現類似的機制,因為IoSession.write()的調用者將完全期望他在他或她的messageSent中寫入的內容(處理方法。
假設您正在實現一個將String轉換為char []的過濾器。您的過濾器的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)); }
String-to-ByteBuffer轉換怎麽樣?我們可以更有效率,因為我們不需要重建原始消息(String)。但是,它比前一個例子稍微復雜一些:
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); } // 不要這樣做 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塊?幸運的是,你不必。這是處理空緩沖區的黃金法則:
1.如果您的過濾器即使緩沖區為空也沒有任何問題,您根本不需要添加if塊。
2.如果過濾器放在ProtocolCodecFilter之後,則根本不需要添加if塊。
3,.否則,您需要if塊。
如果你需要if塊,請記住你並不總是需要按照上面的例子。只要過濾器沒有引發意外異常,您就可以檢查緩沖區是否為空。
Mina文檔 05-過濾器