Filters
IoFilter 是MINA框架中一個核心的部分,如下圖,對間於IoService和IoHandle之間,用於過濾所有的I/O事件和請求,其扮演的角色就像J2EE中的Servlet。
MINA提供不少現成的過濾器:
1、LoggingFilter :日志過濾器,用於記錄所有的事件和請求日志.
2、ProtocolCodecFilter:規約解析過濾器,用來將所有收到的ByteBuffer內容轉換為POJO消息(對象),實現往來報文的編碼和解碼;
3、CompressionFilter:壓縮過濾器;
4、SSLFilter
…
ProtocolCodecFilter
相對比較常用的是ProtocolCodecFilter,下面主要介紹一下ProtocolCodecFilter的使用:
還是以官方幫助文檔中例子來說明(http://mina.apache.org/chapter-11-codec-filter.html)
這是一個圖片服務器程序,請求圖片的下行報文格式:
width: 請求圖片的寬度
height: 請求圖片的高度
numchars: 生成的字節個數
服務端返回兩張圖片:
length1: 圖片1的大小
image1: 圖片1(PNG格式)
length2: 圖片2的大小
image2: 圖片2(PNG格式)
現在如果想通過MINA框架來實現基於這一簡單規約的編解碼通信功能,應該如何做呢?
1: public class ImageServer {
2: public static final int PORT = 33789;
3:
4: public static void main(String[] args) throws IOException {
5: ImageServerIoHandler handler = new ImageServerIoHandler();
6: NioSocketAcceptor acceptor = new NioSocketAcceptor();
7: acceptor.getFilterChain().addLast("protocol", new ProtocolCodecFilter(new ImageCodecFactory(false)));
8: acceptor.setLocalAddress(new InetSocketAddress(PORT));
9: acceptor.setHandler(handler);
10: acceptor.bind();
11: System.out.println("server is listenig at port " + PORT);
12: }
13: }
這里先來看和Filter有關的部分:
acceptor.getFilterChain().addLast("protocol", new ProtocolCodecFilter(new ImageCodecFactory(false)));
在acceptor的Filter鏈中加入我們自己的過濾器,一個ProtocolCodecFilter的實現,這里的ImageCodecFactory又是什么呢?
1: public class ImageCodecFactory implements ProtocolCodecFactory {
2: private ProtocolEncoder encoder;
3: private ProtocolDecoder decoder;
4:
5: public ImageCodecFactory(boolean client) {
6: if (client) {
7: encoder = new ImageRequestEncoder();
8: decoder = new ImageResponseDecoder();
9: } else {
10: encoder = new ImageResponseEncoder();
11: decoder = new ImageRequestDecoder();
12: }
13: }
14:
15: public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
16: return encoder;
17: }
18:
19: public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
20: return decoder;
21: }
22: }
ImageCodecFactory是對接口ProtocolCodecFactory 的實現,是用來構建Filter的。ProtocolCodecFactory 接口只有兩個方法:
1: public interface ProtocolCodecFactory {
2:
3: public ProtocolEncoder getEncoder(IoSession is) throws Exception;
4:
5: public ProtocolDecoder getDecoder(IoSession is) throws Exception;
6: }
7:
沒錯,這個規約編解碼工廠需要裝配一個編碼器(Encoder)和一個解碼器(Decoder):
編碼器:
1: public class ImageRequestEncoder implements ProtocolEncoder {
2:
3: public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
4: ImageRequest request = (ImageRequest) message;
5: IoBuffer buffer = IoBuffer.allocate(12, false);
6: buffer.putInt(request.getWidth());
7: buffer.putInt(request.getHeight());
8: buffer.putInt(request.getNumberOfCharacters());
9: buffer.flip();
10: out.write(buffer);
11: }
12:
13: public void dispose(IoSession session) throws Exception {
14: // nothing to dispose
15: }
16: }
解碼器:
1: public class ImageRequestDecoder extends CumulativeProtocolDecoder {
2:
3: protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
4: if (in.remaining() >= 12) {
5: int width = in.getInt();
6: int height = in.getInt();
7: int numberOfCharachters = in.getInt();
8: ImageRequest request = new ImageRequest(width, height, numberOfCharachters);
9: out.write(request);
10: return true;
11: } else {
12: return false;
13: }
14: }
15: }
這里解碼器不是直接從ProtocolDecoder繼承的,為什么呢?因為實際中接受的一個數據包並不能保證包含完整的一幀報文,就是所謂的斷幀的情況,如果用CumulativeProtocolDecoder,就不需要自己處理這種情況了,MINA框架會將未解碼的數據保留,等下一包數據到來后繼續嘗試解碼;
這里編碼器的encode和解碼器的doDecode方法就是實際用來進行應用層規約編解碼的;其中ImageResuest是下行請求規約對應POJO.
整個類的協助關系如下圖所示:
Filter過濾器處理完后,就交給Handler,做進一步業務處理;
Response部分的就不多羅嗦了,可以看這里
至此對MINA框架用過的一些東西,從使用指南的角度做了一些總結,還有很多方面還沒有用過,先留一個坑,等來日填補吧。MINA框架最吸引我的是這種設計思想,將通信、規約解析、業務處理分離得恰到好處,既不影響性能又方便擴展和替換。下一步希望從源代碼的角度,學習一下其內部的實現思想。