Mina框架IoHandler与IoProcessor详解

我们已经知道,IoHandler是开发网络应用程序的时候,与实际业务逻辑相关的组件,即属于Mina核心框架之外的应用层组件。从Mina 官方文档上,我们几乎没有看到对IoProcessor的说明,实际上IoProcessor对实际使用Mina框架的开发人员透明,无需你去了解它的实现逻辑,它在Mina中用来处理实际的I/O操作。
我们分析的思路是,先分别对IoHandler与IoProcessor进行单独分析,然后再阐述它们之间的不同以及联系。

  • IoHandler

当我们通过IoSession执行相关操作的时候,如写数据,这些事件会触发Mina框架抽象的IoService实例,从而调用Mina框架底层的相关组件进行处理。这时,配置的IoHandler就被用来处理Mina所触发的相关事件,处理这些事件的操作被抽象出来。
实际上,IoHandler的继承层次非常简单,也说明了基于Mina框架开发实际网络应用程序,对业务逻辑的处理也还是相对比较容易的。看一下 IoHandler的继承层次,如图所示:

IoHandler接口所定义的操作,一共定义了7个处理事件的操作,如下所示:

1 public interface IoHandler {
2 void sessionCreated(IoSession session) throws Exception;
3 void sessionClosed(IoSession session) throws Exception;
4 void sessionIdle(IoSession session, IdleStatus status) throws Exception;
5 void exceptionCaught(IoSession session, Throwable cause) throws Exception;
6 void messageReceived(IoSession session, Object message) throws Exception;
7 void messageSent(IoSession session, Object message) throws Exception;
8 }

因为IoHandler是一个接口,所以如果使用该接口我们就必须实现所有的方法,MIna通过使用IoHandlerAdapter来默认实现 IoHandler接口,并在IoHandlerAdapter中全部给出空实现,如果我们要开发自己的IoHandler,可以继承自IoHandlerAdapter,根据需要选择重写指定的处理Mina事件的方法,而对于你不感兴趣的方法就默认不给予实现(默认使用 IoHandlerAdapter的空实现)。
那么,Mina调用IoHandler的时机是什么呢?又是如何调用的呢?
其实,根据Mina的架构,我们知道,在客户端主动发起I/O操作请求以后,会等待Mina触发相应的事件,在经过一组IoFilter之后,在 IoFilter链的最后一个IoFilter被调用将要结束的时候,会调用我们注册的IoHandler实现,经过处理来满足实际业务逻辑需要。我们可以在DefaultIoFilterChain中看到一个内部IoFilter实现类TailFilter,在该类里调用了 IoHandler封装的逻辑,代码如下所示:

01 private static class TailFilter extends IoFilterAdapter {
02 @Override
03 public void sessionCreated(NextFilter nextFilter, IoSession session) throwsException {
04 try {
05 session.getHandler().sessionCreated(session);
06 } finally {
07 // Notify the related future.
08 ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);
09 if (future != null) {
10 future.setSession(session);
11 }
12 }
13 }
14
15 @Override
16 public void sessionOpened(NextFilter nextFilter, IoSession session) throwsException {
17 session.getHandler().sessionOpened(session);
18 }
19
20 @Override
21 public void sessionClosed(NextFilter nextFilter, IoSession session) throwsException {
22 AbstractIoSession s = (AbstractIoSession) session;
23 try {
24 s.getHandler().sessionClosed(session);
25 } finally {
26 try {
27 s.getWriteRequestQueue().dispose(session);
28 } finally {
29 try {
30 s.getAttributeMap().dispose(session);
31 } finally {
32 try {
33 // Remove all filters.
34 session.getFilterChain().clear();
35 } finally {
36 if (s.getConfig().isUseReadOperation()) {
37 s.offerClosedReadFuture();
38 }
39 }
40 }
41 }
42 }
43 }
44
45 @Override
46 public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception {
47 session.getHandler().sessionIdle(session, status);
48 }
49
50 @Override
51 public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception {
52 AbstractIoSession s = (AbstractIoSession) session;
53 try {
54 s.getHandler().exceptionCaught(s, cause);
55 } finally {
56 if (s.getConfig().isUseReadOperation()) {
57 s.offerFailedReadFuture(cause);
58 }
59 }
60 }
61
62 @Override
63 public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
64 AbstractIoSession s = (AbstractIoSession) session;
65 if (!(message instanceof IoBuffer)) {
66 s.increaseReadMessages(System.currentTimeMillis());
67 } else if (!((IoBuffer) message).hasRemaining()) {
68 s.increaseReadMessages(System.currentTimeMillis());
69 }
70
71 try {
72 session.getHandler().messageReceived(s, message);
73 } finally {
74 if (s.getConfig().isUseReadOperation()) {
75 s.offerReadFuture(message);
76 }
77 }
78 }
79
80 @Override
81 public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
82 session.getHandler().messageSent(session, writeRequest.getMessage());
83 }
84
85 @Override
86 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
87 nextFilter.filterWrite(session, writeRequest);
88 }
89
90 @Override
91 public void filterClose(NextFilter nextFilter, IoSession session) throws Exception {
92 nextFilter.filterClose(session);
93 }
94 }

在上面的代码中,正好调用了IoHandler接口定义的7个处理事件的方法。如果你还想知道IoFilterChain实例是在何时被调用的, 可以跟踪Mina的源码。
* IoProcessor

基于网络的端到端的通信,Mina通过一个IoSession对象(任何获取到一个IoSession实例的持有者都可以)来间接执行 I/O操作,如发送数据、读取数据等。在Mina内部,当一个IoSession调用对应的方法,则直接触发IoProcessor来对指定的事件进行处理,它基于Ractor模式来简化网络传输的实现(事实上,Java NIO就是基于Reactor模式实现,属于同步非阻塞IO模式)。
我们看一下IoProcessor相关类的继承关系,如图所示:



看到上面AbstractPollingConnectionlessIoAcceptor,我们知道,它同时也是IoService的实现,用于网络通信中的服务端,处理接收请求。可见,对于基于UDP/IP的传输,IoAcceptor和IoProcessor的处理是实现在一起的,可能实际处理的逻辑本身比较简单,放到一起能够更好地表达它们之间的紧密联系。
下面我们看一下IoProcessor接口的定义,如下所示:

01 public interface IoProcessor<S extends IoSession> {
02 boolean isDisposing();
03 boolean isDisposed();
04 void dispose();
05 void add(S session);
06 void flush(S session);
07 void write(S session, WriteRequest writeRequest);
08 void updateTrafficControl(S session);
09 void remove(S session);
10 }

我们根据上面接口总结一下,一个IoProcessor实际处理了如下内容:

  1. 添加IoSession实例,主要是使用IoProcessor内部的一个IoSession队列newSessions来存放。
  2. Flush指定IoSession实例到IoProcessor内部的flushingSessions队列。
  3. Write一个IoSession实例对应的WriteRequest,主要是将一个WriteRequest加入到 IoSession实例所持有的WriteRequestQueue writeRequestQueue队列。至于加入到队列的请求何时处理,其实我们可以参考IoProcessor的实现AbstractPollingIoProcessor 类,其内部有一个org.apache.mina.core.polling.AbstractPollingIoProcessor.Processor 线程类,这个线程会在调用一个IoProcessor的方法public final void add(S session)的时候被启动(实际,在调用dispose()、add(S session)、remove(S session)这三个方法的时候,都会尝试着去启动一个Processor线程,如果没有启动则会启动这个线程),然后反复循环检测并处理队列中的写请求。
  4. 当IoProcessor关闭与一个IoSession实例实例相关的连接,则会将这个IoSession实例从 removingSessions队列中移除。
  5. 控制处理事件的通信量,主要是控制读写:如果没有注册读操作(SelectionKey.OP_READ),则注册一个,否则当一个 读操作已经就绪,则进行读数据的处理;如果没有注册写操作(SelectionKey.OP_WRITE),则注册一个,否则当一个写操 作已经就绪,则进行写数据的处理。
  6. 释放所有与IoProcessor有关的资源。

总结

经过上面的对比,我们已经能够知道IoHandler与IoProcessor的本质区别。
IoHandler是在IoFilterChain执行中最后一个IoFilter中被调用,比如,经过IoFilterChain进行 codec、logging等等操作之后,已经将通信层的数据转化成我们需要的业务对象数据,这时就可以调用我们定义的IoHandler实 现来进行处理。
IoProcessor是与实际的Socket或Channel相关的操作紧密相关的,也就是说,它是支撑Mina进行处理底层实际I/O请 求的处理器。

时间: 2024-09-24 03:40:40

Mina框架IoHandler与IoProcessor详解的相关文章

Bootstrap框架的学习教程详解(二)_javascript技巧

Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷. 一.下载Bootstrap Bootstrap (当前版本 v3.3.0)提供以下几种方式帮你快速上手,每一种方式针对具有不同技能等级的开发者和不同的使用场景. 下载地址:http://v3.bootcss.com/getting-started/ PS:其实我们不用下载bootstrap也可以使用它: Bootst

js验证框架之RealyEasy验证详解_javascript技巧

使用Really_easy_field_validation_with_Prototype进行表单验证,具体内容如下 1.第一步当然是先引入js和css文件. <link href="${ ctx}/skin/css/validation.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="${ c

CI框架整合smarty步骤详解_php实例

本文详细讲述了CI框架整合smarty步骤.分享给大家供大家参考,具体如下: Ci结合smarty的配置步骤: 1. 第一步配置ci和下载smarty的模板个人喜欢用(Smarty-3.1.8)这个版本. 2. 第二部把下载到的smarty版本解压然后把里面的libs文件改名为smarty然后把这个文件拷到ci\application\libraries目录下面 3. 在ci\application\libraries这个目录下面建立一个文件,文件名可以自定义,例如见一个tp.php的文档. 4

CI框架整合smarty步骤详解

本文详细讲述了CI框架整合smarty步骤.分享给大家供大家参考,具体如下: Ci结合smarty的配置步骤: 1. 第一步配置ci和下载smarty的模板个人喜欢用(Smarty-3.1.8)这个版本. 2. 第二部把下载到的smarty版本解压然后把里面的libs文件改名为smarty然后把这个文件拷到ci\application\libraries目录下面 3. 在ci\application\libraries这个目录下面建立一个文件,文件名可以自定义,例如见一个tp.php的文档. 4

基于MVC模式Struts框架研究与应用详解

分布式企业应用软件结构复杂.涉及多种技术,对设计开发人员提出了很高的要求.在此情况下,运用设计模式――可复用的设计方案进行软件的设计开发十分必要.MVC模式已被证明是一种成功的软件设计模式,本文主要讨论了一种实现MVC模式的应用框架――Struts,并通过一个实例展示了Struts框架实现MVC模式的方法. MVC设计模式 MVC(Modle-View-Controller,模型-视图-控制器)模式是Xerox PARC在20世纪80年代为编程语言Smalltalk-80所设计的一种软件设计模式

用模版生成HTML的的框架jquery.tmpl使用详解_jquery

动态请求数据来更新页面是现在非常常用的方法,比如博客评论的分页动态加载,微博的滚动加载和定时请求加载等. 这些情况下,动态请求返回的数据一般不是已拼好的 HTML 就是 JSON 或 XML,总之不在浏览器端拼数据就在服务器端拼数据.不过,从传输量方面来看,返回 HTML 不划算,而在 web 传输方面,现在更多的是使用 JSON 而不是 XML. 浏览器端根据 JSON 生成 HTML 有个很苦恼的地方就是,结构不复杂的时候还好,结构一复杂,就想死了,需要很小心很小心地写出几乎无法维护的 Ja

ThinkPHP框架设计及扩展详解_php实例

ThinkPHP框架是国内知名度很高应用很广泛的php框架,我们从一些简单的开发示例中来深入了解一下这个框架给我们带来的开发便捷性,以及游刃有余的扩展设计.同时也从源码分析的角度看看框架的一些不足,尽量做全面客观的评价.这里假设大家已经使用过ThinkPHP框架,基本使用方法请参考官方文档. 一.框架分层及url路由 框架的安装非常简单,下载后放入web服务器的目录即可,但是建议大家不要用默认的入口文件位置,而是放入单独的目录,便于保护代码和数据.例如我的入口文件和web服务器配置目录在web目

Yii框架的登录流程详解教程

1. 概述 Yii是一个全栈式的MVC框架,所谓全栈式指的是Yii框架本身实现了web开发中所要用到的所有功能,比如MVC,ORM(DAO/ActiveRecord), 全球化(I18N/L10N), 缓存(caching), 基于jQuery Ajax支持(jQuery-based AJAX support), 基于角色的用户验证(authentication and role-based access control), 程序骨架生成器(scaffolding), 输入验证(input va

Android游戏框架LGame的引入详解介绍

框架下载地址:http://code.google.com/p/loon-simple/downloads/list 下面就讲解下项目中怎么引入游戏框架LGame: •新建android项目"LGameTest1",在项目根目录下新建文件夹libs,将下载的LGame框架的jar包放到该文件夹下,然后在Eclipse中右击项目,选择"Build Path->Configure Build Path-->Add External JARs-"选择刚才放到l