I/O Filter Chain层是介于I/O Service层与I/O Handler层之间的一层,从它的命名上可以看出,这个层可以根据实际应用的需要,设置一组IoFilter来对I/O Service层与I/O Handler层之间传输数据进行过滤,任何需要在这两层之间进行处理的逻辑都可以放到IoFilter中。
我们看一下IoFilter的抽象层次设计,如图所示:
通过上述类图可见,要实现一个自定义的IoFilter,一般是直接实现IoFilterAdapter类。同时,Mina也给出了几类常用的开发IoFilter的实现类,如下所示:
- LoggingFilter记录所有事件和请求
- ProtocolCodecFilter将到来的ByteBuffer转换成消息对象(POJO)
- CompressionFilter压缩数据
- SSLFilter增加SSL – TLS – StartTLS支持
想要实现一个自定义的IoFilter实现类,只需要基于上述给出的几个实现类即可。
如果想要实现自己的IoFilter,可以参考如下例子:
1 | public class MyFilter extends IoFilterAdapter { |
3 | public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception { |
5 | nextFilter.sessionOpened(session); |
下面通过一个例子来说明,如何使用IoFilter的实现类。
ProtocolCodecFilter
下面是Mina自带的例子,使用了ProtocolCodecFilter类:
01 | package org.apache.mina.example.gettingstarted.timeserver; |
03 | import java.io.IOException; |
04 | import java.net.InetSocketAddress; |
05 | import java.nio.charset.Charset; |
07 | import org.apache.mina.core.service.IoAcceptor; |
08 | import org.apache.mina.core.session.IdleStatus; |
09 | import org.apache.mina.filter.codec.ProtocolCodecFilter; |
10 | import org.apache.mina.filter.codec.textline.TextLineCodecFactory; |
11 | import org.apache.mina.filter.logging.LoggingFilter; |
12 | import org.apache.mina.transport.socket.nio.NioSocketAcceptor; |
14 | public class MinaTimeServer { |
16 | * We will use a port above 1024 to be able to launch the server with a |
19 | private static final int PORT = 9123 ; |
22 | * The server implementation. It's based on TCP, and uses a logging filter |
23 | * plus a text line decoder. |
25 | public static void main(String[] args) throws IOException { |
27 | IoAcceptor acceptor = new NioSocketAcceptor(); |
30 | acceptor.getFilterChain().addLast( "logger" , new LoggingFilter()); |
31 | acceptor.getFilterChain().addLast( "codec" , new ProtocolCodecFilter( new TextLineCodecFactory(Charset.forName( "UTF-8" )))); |
34 | acceptor.setHandler( new TimeServerHandler()); |
37 | acceptor.getSessionConfig().setReadBufferSize( 2048 ); |
38 | acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10 ); |
41 | acceptor.bind( new InetSocketAddress(PORT)); |
上面设置了两个IoFilter,关键是看如果基于文本行的消息,使用一个ProtocolCodecFilter包裹了一TextLineCodecFactory类的实例,使用起来非常容易。
构造一个ProtocolCodecFilter实例,需要实现一个ProtocolCodecFactory实例,一个ProtocolCodecFactory包含了对消息进行编解码(Codec)的逻辑,这样实现的好处是将编解码的逻辑和IoFilter解耦合。下面看一下类图:
LoggingFilter
如果需要记录通信过程中的事件以及请求,则可以直接使用LoggingFilter类,使用方法可以参考上面的例子。
CompressionFilter
CompressionFilter是与压缩/解压缩数据相关的IoFilter,我们可以看一下该类的构造方法,如下所示:
02 | * Creates a new instance which compresses outboud data and decompresses |
03 | * inbound data with default compression level. |
05 | public CompressionFilter() { |
06 | this ( true , true , COMPRESSION_DEFAULT); |
10 | * Creates a new instance which compresses outboud data and decompresses |
11 | * inbound data with the specified <tt>compressionLevel</tt>. |
13 | * @param compressionLevel the level of compression to be used. Must |
15 | public CompressionFilter( final int compressionLevel) { |
16 | this ( true , true , compressionLevel); |
20 | * Creates a new instance. |
22 | * @param compressInbound <tt>true</tt> if data read is to be decompressed |
23 | * @param compressOutbound <tt>true</tt> if data written is to be compressed |
24 | * @param compressionLevel the level of compression to be used. Must |
26 | public CompressionFilter( final boolean compressInbound, final boolean compressOutbound, final int compressionLevel) { |
27 | this .compressionLevel = compressionLevel; |
28 | this .compressInbound = compressInbound; |
29 | this .compressOutbound = compressOutbound; |
基本上就构造方法参数中指定的3个参数与压缩/解压缩相关:
- compressionLevel
- compressInbound
- compressOutbound
使用的时候也比较简单,只需要创建一个CompressionFilter实例,加入到Filter Chain中即可。
DefaultIoFilterChainBuilder
Mina自带的DefaultIoFilterChainBuilder可以非常容易就可以构建一个Filter Chain,默认在创建IoAcceptor和IoConnector的时候,可以直接通过他们获取到一个DefaultIoFilterChainBuilder的实例,然后调用add*方法设置IoFilter链,如下面代码中示例:
1 | IoAcceptor acceptor = new NioSocketAcceptor(); |
4 | acceptor.getFilterChain().addLast( "logger" , new LoggingFilter()); |
5 | acceptor.getFilterChain().addLast( "codec" , new ProtocolCodecFilter( new TextLineCodecFactory(Charset.forName( "UTF-8" )))); |
下面看一下来自Mina官网的表格,Mina框架也给出了一些典型的IoFilter的实现,引用如下所示: