深入理解Apache Mina (2)---- 与IoFilter相关的几个类

来源:互联网 发布:log4j2 知乎 编辑:程序博客网 时间:2024/04/30 06:35

 从名字上看知道IoFilter应该是一个过滤器,不错,它确实是一个过滤器,它和Servlet中的过滤器类似,主要用于拦截和过滤I/O操作中的各种信息。在Mina的官方文档中已经提到了IoFilter的作用:

  (1)记录事件的日志(这个在本文中关于LoggingFilter的讲述中会提到)

  (2)测量系统性能

  (3)信息验证

  (4)过载控制

  (5)信息的转换 (例如:编码和解码,这个会在关于ProtocolCodecFilter的讲述中会提到)

  (6)和其他更多的信息

  还是上一篇文档一样,先提出几个问题,然后沿着这几个问题的思路一个一个的对IoFilter进行讲解。

  (1)什么时候需要用到IoFilter,如果在自己的应用中不添加过滤器可以吗?

  (2)如果在IoService中添加多个过滤器可以吗?若可以,如何进行添加,这多个过滤  

  器是如何工作的?

  (3)Mina中提供了协议编、解码器,IoFilter也可以实现IO数据的编解码功能,在实际

  的使用中如何选择?

  在开始对上面的问题进行讨论前,为了对IoFilter提供的方法有一个具体的了解,先对Mina自身提供的一个最简单的过滤器进行一些讲解----LoggingFilter(源码在附件中,配有中文翻译)。

  首先还是看一下LoggingFilter中提供的几个方法。列举如下(方法中的参数就不再给出,完整方法的实现请参考附件中LoggingFilter的源码):

  (1)sessionCreated()

  (2)sessionOpened()

  (3)sessionClosed()

  (4)sessionIdle()

  (5)exceptionCaught()

  (6)messageReceived()

  (7)messageSent()

  (8)filterWrite()

  (9)filterClose()

  这几个方法都由相应会话(或者说是连接的状态,读、写、空闲、连接的开闭等)的状态的改变来触发的。当一个会话开启时,LoggingFilter捕获到会话开启的事件,会触发sessionCreated()方法,记录该会话开启的日志信息。同样当一个会话发送数据时,Logging捕获到会话发送消息的事件会记录消息发送的日志信息。这里只是给出messageReceived()的完成方法的实现,其他方法的完整实现请参考附件中 LoggingFilter的源码。

/**
  * 记录会话接收信息时的信息,然后将该信息传递到过滤器链中的下一个过滤器
  * */
 public void messageReceived(NextFilter nextFilter, IoSession session,    Object message) {  
    if (SessionLog.isInfoEnabled(session)) {   SessionLog.info(session, "RECEIVED: " + message);  
    }  nextFilter.messageReceived(session, message); 
} ServerMain: 
public class ServerMain { 
 
 public static void main(String[] args) throws IOException { 
 SocketAddress address = new InetSocketAddress("localhost", 4321); 
 IoAcceptor acceptor = new SocketAcceptor(); 
 IoServiceConfig config = acceptor.getDefaultConfig(); 
 
 // 配置数据的编解码器 
 config.getFilterChain().addLast("codec", 
  new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); 
 
 // 绑定服务器端口 
 acceptor.bind(address, new ServerHandler()); 
 System.out.println(" 服务器开始在 8000 端口监听 ......."); 
 } 
} 
 
ServerHandler: 
public class ServerHandler extends IoHandlerAdapter { 
 
 // 创建会话 
 public void sessionOpened(IoSession session) throws Exception { 
 System.out.println(" 服务器创建了会话 "); 
 session.write(" 服务器创建会话时发送的信息 。"); 
 } 
 
 // 发送信息 
 public void messageSent(IoSession session, Object message) throws Exception { 
 } 
 
 // 接收信息 
 public void messageReceived(IoSession session, Object message) 
  throws Exception { 
 } 
} 
 
ClientMain: 
public class ClientMain { 
 
 public static void main(String[] args) { 
 
 SocketAddress address = new InetSocketAddress("localhost", 4321); 
 IoConnector connector = new SocketConnector(); 
 IoServiceConfig config = connector.getDefaultConfig(); 
 
 // 配置数据的编解码器 
 config.getFilterChain().addLast("codec", 
  new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); 
  
 config.getFilterChain().addLast("logger", new LoggingFilter()); 
 
 // 连接到服务器 
 connector.connect(address, new ClientHandler()); 
 System.out.println(" 已经连接到了服务器 " + address); 
 } 
} 
 
ClientHandler: 
public class ClientHandler extends IoHandlerAdapter { 
 
 // 发送信息 
 public void messageSent(IoSession session, Object message) throws Exception { 
 } 
 
 // 接收信息 
 public void messageReceived(IoSession session, Object message) 
  throws Exception { 
 System.out.println(" 客户端接收到的服务器的信息是 " + message); 
 } 
} 

 ProtocolFilter:该类是Mina提供的一个协议编解码器,在socket通信中最重要的就是协议的编码和解码工作,Mina提供了几个默认的编解码器的实现,在下面的例子中使用了 ObjectSerializationCodecFactory,这是Mina提供的一个Java对象的序列化和反序列化方法。使用这个编解码器,你可以在你的Java客户端和服务器之间传递任何类型的Java对象。但是对于不同的平台之间的数据传递需要自己定义编解码器,关于这点的介绍会在后续的文档中给出。

  为了更加清楚的理解这个过滤器的作用我们先来看一个简单的例子,这个例子的功能就是服务器在客户端连接到服务器时创建一个会话,然后向客户端发送一个字符串(完整的源码在附件中,这里只给出程序的简要内容):

  Java代码  

 LoggingFilter继承与 IoFilterAdpater,IoFilterAdpater是IoFilter的一个实现类,该类只是提供了IoFilter方法的简单实现 ----将传递到各方法中的消息转发到下一个过滤器中。你可以根据自己的需求继承IoFilterAdpater,并重写相关的方法。 LoggingFilter就是重写了上面提到的几个方法,用于记录当前的会话各种操作的日志信息。通过上面的例子,我们可以大体的了解了 IoFilter的基本功能:根据当前会话状态,来捕获和处理当前会话中所传递的消息。

  IoFilter的UML图如下:

  从上面的类图我们可以清晰的看到IoFilter是一个接口,它有两个具体的实现类:

  IoFilterAdpater:该类提供了IoFilter所有方法的方法体,但是没有任何逻辑处理,你可以根据你具体的需求继承该类,并重写相关的方法。IoFilterAdpater是在过滤器中使用的较多的一个类。

  ReferenceCountingIoFilter:该类封装IoFilter的实例,它使用监视使用该IoFilter的对象的数量,当没有任何对象使用该IoFilter时,该类会销毁该IoFilter。

  IoFilterAdpater有三个子类,它们的作用分别如下:

  LoggingFilter:日志工具,该类处理记录IoFilter每个状态触发时的日志信息外不对数据做任何处理。它实现了IoFilter接口的所有方法。你可以通过阅读该类的源码学习如何实现你自己的IoFilter。

  ExcuterFilter:这个Mina自身提供的一个线程池,在 Mina中你可以使用这个类配置你自己的线程池,由于创建和销毁一个线程,需要耗费很多资源,特别是在高性能的程序中这点尤其重要,因此在你的程序中配置一个线程池是很重要的。它有助于你提高你的应用程序的性能。关于配置Mina的线程池在后续的文档中会给出详细的配置方法。

 其中ServerMain和ClientMain分别是服务器和客户端的主程序,ServerHandler和ClientHandler是服务器和客户端的数据处理句柄,关于IoHandler会在后面的文档中做详细的讲解,这里只是简单说明一下,IoHandler主要是对数据进行逻辑操作,也可以理解为程序的业务逻辑层。其中:

  Java代码  

// 配置数据的编解码器 
 config.getFilterChain().addLast("codec", 
  new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); 

 这行代码的功能是将网络传输中的数据在发送时编码成二进制数据,解码时将二进制数据还原成一个对象或者是基本类型的数据。

  Java代码


运行这个程序会得到如下结果: 
 已经连接到了服务器 localhost/127.0.0.1:4321 
2009-7-9 23:36:46 org.apache.mina.util.SessionLog info 
信息: [localhost/127.0.0.1:4321] CREATED 
2009-7-9 23:36:46 org.apache.mina.util.SessionLog info 
信息: [localhost/127.0.0.1:4321] OPENED 
2009-7-9 23:36:46 org.apache.mina.util.SessionLog info 
信息: [localhost/127.0.0.1:4321] RECEIVED:  服务器创建会话时发送的信息 。 
 客户端接收到的服务器的信息是  服务器创建会话时发送的信息 。 

http://tech.ddvip.com/2009-09/1253100314133128_2.html