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