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的实现,引用如下所示: