Mina中的过滤器处于IoService与IoHandler之间,用于过滤每一个I/O事件。本文分析Mina中的过滤器是怎么串起来的?

前面提到了IoFilter,FilterChain等接口和类,在分析过滤器链怎么串起来之前,有必要看一下这些接口和类之间的关系。

如上图所示:

FilterChain是由一个个Entry串起来的,EntryImpl是Entry的实现;

从EntryImpl中可以获取到Filter与NextFilter,NextFilter相当于那根线(指针);

有两个特殊的Entry,里面的Filter分别是HeadFilter和TailFilter,我们添加的Filter都处于这两个Filter之间;

每做完一个Entry,NextFilter会回到FilterChain处理下一个Entry(处理顺序如下图所示)。

由上图可知:

(1)当消息到来时,触发过滤器链的fireXXX事件(这一步一般在processor里面触发);

(2)从过滤器链获取上头结点Entry,从头结点Entry中取出filter和nextFilter;

(3)Filter处理后,交由nextFilter处理,nextFilter并不是一个真正的Filter,它决定这个过滤器链的走向,在这里它是返回到过滤器链;

(4)过滤器链通过nextFilter指针得到下一个entry,重复执行(2)、(3),直到每个Entry都处理完。

这里抛出两个问题:

1、如何保证新加入的过滤器在HeadFilter与TailFilter之间?

2、nextFilter一定是从左向右的顺序吗?

3、TailFilter调用了IoHandler吗?

对于第一个问题,答案在EntryImpl的构造方法里面

// EntryImpl构造方法
private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) {
......
this.prevEntry = prevEntry;
this.nextEntry = nextEntry;
this.name = name;
this.filter = filter;
this.nextFilter = new NextFilter() {
......
};
} //FilterChain构造方法
public DefaultIoFilterChain(AbstractIoSession session) {
if (session == null) {
throw new IllegalArgumentException("session");
} this.session = session;
head = new EntryImpl(null, null, "head", new HeadFilter());
tail = new EntryImpl(head, null, "tail", new TailFilter());
head.nextEntry = tail;
}

在FilterChain构造方法里面初始化了两个Entry:

我们一般调用IoFilterChain的如下方法添加过滤器

void addFirst(String name, IoFilter filter);
void addLast(String name, IoFilter filter);
void addBefore(String baseName, String name, IoFilter filter);
void addAfter(String baseName, String name, IoFilter filter);

这里以addLast为例,先看看addLast方法的实现

public synchronized void addFirst(String name, IoFilter filter) {
checkAddable(name);
register(head, name, filter);
} private void register(EntryImpl prevEntry, String name, IoFilter filter) {
EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
......
prevEntry.nextEntry.prevEntry = newEntry;
prevEntry.nextEntry = newEntry;
name2entry.put(name, newEntry);
......
}

从代码一目了然,这就是一个简单的链表操作,在这里第一个问题回答完毕。

对于第二个问题答案是否定的。从IoFilter接口可以看出,一共处理以下几种事件:

sessionCreated
sessionOpened
sessionClosed
sessionIdle
exceptionCaught
messageReceived
messageSent
filterClose
filterWrite
前面FilterChain的构造方法中,省略了NextFilter的实现,这里补上

 this.nextFilter = new NextFilter() {
public void sessionCreated(IoSession session) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextSessionCreated(nextEntry, session);
} public void sessionOpened(IoSession session) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextSessionOpened(nextEntry, session);
} public void sessionClosed(IoSession session) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextSessionClosed(nextEntry, session);
} public void sessionIdle(IoSession session, IdleStatus status) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextSessionIdle(nextEntry, session, status);
} public void exceptionCaught(IoSession session, Throwable cause) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextExceptionCaught(nextEntry, session, cause);
} public void messageReceived(IoSession session, Object message) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextMessageReceived(nextEntry, session, message);
} public void messageSent(IoSession session, WriteRequest writeRequest) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextMessageSent(nextEntry, session, writeRequest);
} public void filterWrite(IoSession session, WriteRequest writeRequest) {
Entry nextEntry = EntryImpl.this.prevEntry;
callPreviousFilterWrite(nextEntry, session, writeRequest);
} public void filterClose(IoSession session) {
Entry nextEntry = EntryImpl.this.prevEntry;
callPreviousFilterClose(nextEntry, session);
}
}

可以看出filterWrite与filterClose是反向的,其他都是正向的。

对于第三个问题,直接看TailFilter的代码即可:

public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
AbstractIoSession s = (AbstractIoSession) session;
if (!(message instanceof IoBuffer)) {
s.increaseReadMessages(System.currentTimeMillis());
} else if (!((IoBuffer) message).hasRemaining()) {
s.increaseReadMessages(System.currentTimeMillis());
} try {
session.getHandler().messageReceived(s, message);
} finally {
if (s.getConfig().isUseReadOperation()) {
s.offerReadFuture(message);
}
}
}

确实调用了handler来处理真正的请求。

总结一下:FilterChain是由Entry组成一个链表,HeadFilter与TailFilter所在Entry分别是链表的首尾,HeadFilter与processor相连,TailFilter与handler相连,添加Filter的操作实际上是普通的链表插入操作。FilterChain可以触发多种事件,每种事件到来时Filter的顺序是正序还是倒序由nextFilter决定。

Apache Mina Filter的更多相关文章

  1. Apache MiNa 实现多人聊天室

    Apache MiNa 实现多人聊天室 开发环境: System:Windows JavaSDK:1.6 IDE:eclipse.MyEclipse 6.6 开发依赖库: Jdk1.4+.mina-c ...

  2. Apache Mina(一)

    原文链接:http://www.cnblogs.com/xuekyo/archive/2013/03/06/2945826.html Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应 ...

  3. Apache Mina 入门实例

    这个教程是介绍使用Mina搭建基础示例.这个教程内容是以创建一个时间服务器. 以下是这个教程需要准备的东西: MINA 2.0.7 Core JDK 1.5 或更高 SLF4J 1.3.0 或更高 L ...

  4. Apache Mina原理及典型例子分析

    Apache Mina ,一个高性能 Java 异步并发网络通讯框架.利用 Mina 可以高效地完成以下任务: TCP/IP 和 UDP/IP 通讯 串口通讯 VM 间的管道通讯 SSL/TLS JX ...

  5. 网络通信框架Apache MINA

    Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络 ...

  6. Apache Mina入门实例

    一.mina是啥 ApacheMINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可扩展性的网络应用程序.它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的 ...

  7. Apache Mina -2

    我们可以了解到 mina是个异步通信框架,一般使用场景是服务端开发,长连接.异步通信使用mina是及其方便的.不多说,看例子. 本次mina 使用的例子是使用maven构建的,过程中需要用到的jar包 ...

  8. Apache Mina UDP连接目标服务器地址时出现异常

    俩种情形,第一种是开始连接时候就没连上服务器:第二种是服务器关闭连接,出现的异常: 第一种: java.lang.reflect.InvocationTargetException at sun.re ...

  9. Apache Mina入门

    Mina第一次听到这个名称的时候,我以为是个MM的名字米娜,后来才知道… Apache MINA(Multipurpose Infrastructure for Network Application ...

随机推荐

  1. jinja模板语言

    模板 要了解jinja2,那么需要先理解模板的概念.模板在Python的web开发中广泛使用,它能够有效的将业务逻辑和页面逻辑分开,使代码可读性增强.并且更加容易理解和维护. 模板简单来说就是一个其中 ...

  2. 内置函数bytes()

    a=b'\x00\x9c@c' print a[3]#99,c的ascii码是99 print a[1]#156 并且byte是无法修改的 c[1]=155 Traceback (most recen ...

  3. 使用Docx4j创建word文档

    原文标题:Creating Word documents with Docx4j 原文链接:http://blog.iprofs.nl/2012/09/06/creating-word-documen ...

  4. 配置apache使用https访问

    准备 yum install mod_ssl openssl 生成一个自签名证书 cd /etc/pki/CA 1.生成2048位的加密私钥 openssl genrsa -out server.ke ...

  5. springcloud配置详解

    Spring Boot的配置参考Spring Boot系列文章,这里只对Spring Cloud用到的配置解释. spring.application.name:配置应用名称,在注册中心中显示的服务注 ...

  6. 探秘Java类加载

    Java是一门面向对象的编程语言. 面向对象以抽象为基础,有封装.继承.多态三大特性. 宇宙万物,经过抽象,均可归入相应的种类.不同种类之间,有着相对井然的分别. Java中的类,便是基于现实世界中的 ...

  7. LeetCode(20):有效的括号

    Easy! 题目描述: 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. 左括号必须以正确的顺序闭 ...

  8. 使用Ocelot构建GateWay

    添加Nuget包:Ocelot 添加配置文件Ocelot.json 具体配置可以看另一篇Ocelot配置 Json配置文件主要包含两个根节点: ReRoutes:路由重定向配置 都是数组结构 可以配置 ...

  9. EntityFramework 系列:实体类配置-根据依赖配置关系和关联

    EF实体类的配置可以使用数据注释或Fluent API两种方式配置,Fluent API配置的关键在于搞清实体类的依赖关系,按此方法配置,快速高效合理.为了方便理解,我们使用简化的实体A和B以及A.B ...

  10. vuejs、eggjs、mqtt

    vuejs.eggjs.mqtt全栈式开发设备管理系统 vuejs.eggjs.mqtt全栈式开发简单设备管理系统 业余时间用eggjs.vuejs开发了一个设备管理系统,通过mqtt协议上传设备数据 ...