Mina源码阅读笔记(七)—Mina的拦截器FilterChain
Filter我们很熟悉,在Mina中,filter chain的用法也类似于Servlet的filters,这种拦截器的设计思想能够狠轻松的帮助我们实现对资源的统一处理。我们先大致连接下mina中的filter能给我们带来什么。
- LoggingFilter logs all events and requests.
- ProtocolCodecFilter converts an incoming ByteBuffer into message POJO and vice versa.
- CompressionFilter compresses all data.
- SSLFilter adds SSL - TLS - StartTLS support.
- and many more!
当然这中间最实用,而且源码篇幅最多的就是对codec的拦截器,这部分的应用就是可以实现自定义的编码器和解码器,并附上自定义的协议来进行通信。这部分的应用可以看:《Mina实现自定义协议的通信》
在Mina源码中,对filter的描述主要分两部分,org.apache.mina.core.filterchain以及org.apache.mina.filter.*这两部分。在核心包里主要定义了规则,然后再filter包中进行具体的实现。在讲filter的时候我们需要分清楚filter和filter chain的区别,在chain中加载的是filter,所以filter的生命周期也容易理解,加载到chain中的为active,否则就在生命周期之外。

上图仅org.apache.mina.core.filterchain内的部分关联(ReferenceCountingFilter除外),不过弄明白图上画的这些类的作用和实现原理就基本能明白整个filter的内容,后面的各种filter都是通过IoFilterAdapter派生而来。这也是我们很熟悉的适配器模式的应用。
我们先来看IoFilter,IoFilter加载到chain需经历如下过程:
1、 调用init方法,被ReferenceCountingFilter初始化(此时未加载到chain)
2、 调用onPreAdd方法,告诉filter,将要被加载到chain中去
3、 当filter被加载到chain中,filter chain开始正式起作用
4、 调用onPostAdd方法,做一些加载完成的后处理。
这样的处理方式非常的常用,在Android中的asynctask好像经常会有类似的用法,执行前、执行中、执行后分别处理。其实也不用说那么远,mina中,在handler中处理session的连接也分session
create,session open等等。在IoFilter中有一个内部接口NextFilter,用来引用在chain中的下一个filter(这个next
filter会在当前的filter中被用到,所以要这么设计)。并且,在next接口中,除了上面提到的加载到chain的方法没有之外,其他的都与外部类一致。
我们再来看IoFilter的实现类DefaultIoFilter。我们要提一下这个类,之前我们介绍的无论是service还是session都没有让开发者去重写或者继承,而这里不一样,由于这个类是一个适配器的设计模式,因为必然需可以由有大量的实现方法去充实它。所以在mina官网的user guide上给出了如何去继承这个adapter,具体可见:http://mina.apache.org/mina-project/userguide/ch5-filters/ch5-filters.html
我们可以注意到,DefaultIoFilter的方法里几乎都为空,什么都没有做,最多来一句:
public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
nextFilter.sessionCreated(session);
}
这样做就一个原因摆明了让其他类去做具体的实现,同时也可以让开发者自己去实现。注意,那些未实现的方法都是跟filter生命周期有关的,而receive和send这样的方法都会由next
filter来实现。
接下来我们看IoFilterChain,这个容器装载了我们添加的各种拦截器,每个session都有一个拦截器,这是一对一的关系,当然不要忘记了,拦截器的最后一步是IoHandle,这个我们在之前就说过。我们还是稍稍关注一下这个接口中的内部类Entry,这是一个name-filter对,存放在chain中,好比一个map,给filter一个名字。这节最主要的就是DefaultIoFilterChain,他是整个chain能实现起来的中心,我们主要是看mina是如何给这个filter排序的。
我们截一段代码,Entry的构造方法:
private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) {
if (filter == null) {
throw new IllegalArgumentException("filter");
}
if (name == null) {
throw new IllegalArgumentException("name");
}
this.prevEntry = prevEntry;
this.nextEntry = nextEntry;
this.name = name;
this.filter = filter;
this.nextFilter = new NextFilter() {
public void sessionCreated(IoSession session) {
Entry nextEntry = EntryImpl.this.nextEntry;
callNextSessionCreated(nextEntry, session);
}
主要看构造方法里的这几个参数,后面的两个我们在Entry接口的时候提过,name-filter对,所以这两个必须要,否则抛异常。那前面两个参数从命名中我们就能看见顺序了,继续往下看,我们现在来看DefaultIoFilterChain(Entry是DefaultIoFilterChain的一个内部类)的构造方法:
private final Map<String, Entry> name2entry = new ConcurrentHashMap<String, Entry>();
/** The chain head */
private final EntryImpl head;
/** The chain tail */
private final EntryImpl tail;
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;
}
很明显,这个chain在初始化的时候只有这两个entry,一头一尾,并且这个一头一尾属于唯一一个和DefaultIoFilterChain绑定的session。这个是不是很像链表。所以你就很容易理解AddFirst和AddLast方法是怎么实现的了:
public synchronized void addFirst(String name, IoFilter filter) {
checkAddable(name);
register(head, name, filter);
}
private void checkAddable(String name) {
if (name2entry.containsKey(name)) {
throw new IllegalArgumentException("Other filter is using the same name '" + name + "'");
}
}
private void register(EntryImpl prevEntry, String name, IoFilter filter) {
EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
try {
filter.onPreAdd(this, name, newEntry.getNextFilter());
} catch (Exception e) {
throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);
}
prevEntry.nextEntry.prevEntry = newEntry;
prevEntry.nextEntry = newEntry;
name2entry.put(name, newEntry);
try {
filter.onPostAdd(this, name, newEntry.getNextFilter());
} catch (Exception e) {
deregister0(newEntry);
throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);
}
}
看了代码是不是就一目了然了,这不就是数据结构里我们常用的双向链表。所以数据结构不是白学的,软件设计上经常会用到。这个类里基本就是对链表的操作,只要对双向链表的指针比较清楚的,读懂也应该没什么问题。
提一下IoFilterChainBuilder和DefaultIoFilterChainBuilder。这又是一组继承关系,DefaultIoFilterChainBuilder的实现和DefaultIoFilterChain很像,几乎一样。这也是能够用来做拦截器链的,但是它和DefaultIoFilterChain还是有不同:
l DefaultIoFilterChainBuilder不管理IoFuture的生命周期
l DefaultIoFilterChainBuilder不会影响已经创建好的session
我们来看一下IoService中的getFilterChain:
/**
* A shortcut for <tt>( ( DefaultIoFilterChainBuilder ) </tt>{@link #getFilterChainBuilder()}<tt> )</tt>.
* Please note that the returned object is not a <b>real</b> {@link IoFilterChain}
* but a {@link DefaultIoFilterChainBuilder}. Modifying the returned builder
* won't affect the existing {@link IoSession}s at all, because
* {@link IoFilterChainBuilder}s affect only newly created {@link IoSession}s.
*
* @throws IllegalStateException if the current {@link IoFilterChainBuilder} is
* not a {@link DefaultIoFilterChainBuilder}
*/
DefaultIoFilterChainBuilder getFilterChain();
得到的是DefaultIoFilterChainBuilder而不是IoFilterChain。那如果你要IoFilterChain就需要用下面的方法来built:
void setFilterChainBuilder(IoFilterChainBuilder builder);
不过我看官网上也是用默认的DefaultIoFilterChainBuilder来生成chain。可能后面只要管理到handler就行了,而且一般的应用中,一条通道中也只用一个session。
Filter只讲到这里了,至于那十几个常用的我觉得没必要写了,他们总有那么一个类要去继承IoFilterAdapter,然后再不断的派生开来,所以如果你要用到哪个就再自己读就行了。我觉得这部分还是注重应用为主,至少我不关心这些实现,它和通信的关系就不是很大了。
Mina源码阅读笔记(七)—Mina的拦截器FilterChain的更多相关文章
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- Mina源码阅读笔记(一)-整体解读
今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...
- Mina源码阅读笔记(二)- IoBuffer的封装
在阅读IoBuffer源码之前,我们先看Mina对IoBuffer的描述:A byte buffer used by MINA applications. This is a replacement ...
- Mina源码阅读笔记(三)-Mina的连接IoAccpetor
其实在mina的源码中,IoService可以总结成五部分service责任.Processor线程处理.handler处理器.接收器和连接器,分别对应着IoService.IoProcessor.I ...
- Mina源码阅读笔记(六)—Mina异步IO的实现IoFuture
IoFuture是和IoSession紧密相连的一个类,在官网上并没有对它的描述,因为它一般不会显示的拿出来用,权当是一个工具类被session所使用.当然在作用上,这个系列可并不简单,我们先看源码的 ...
- Mina源码阅读笔记(五)—Mina对连接的操作IoSession
IoSession是Mina管理两端的一个重要部分,也是Mina的核心,Session具有了生命周期的概念,它的生命周期和连接时紧密相关的,这点在后面的介绍中会涉及.另外,好像hibernate中也有 ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector1
上一篇写的是IoAcceptor是服务器端的接收代码,今天要写的是IoConnector,是客户端的连接器.在昨天,我们还留下一些问题没有解决,这些问题今天同样会产生,但是都要等到讲到session的 ...
- jdk源码阅读笔记-LinkedHashMap
Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
随机推荐
- linux中exec和xargs命令的区别和优劣分析
find的exec及ok命令 exec命令的格式为: exec command {} \; exec后面跟着的是操作命令,然后跟着{}表示每一个参数,然后空格,然后"\;".{}之 ...
- 剑指Offer——丑数
剑指Offer--丑数 前言 参照<剑指Offer>,通过洞悉其思想并消化吸收,改为java实现,供自己以后巩固. package cn.edu.ujn.offersword; i ...
- 01_数据库连接池,数据源,ResultSetMetaData,jdbc优化
一.数据库连接池 1. 什么是连接池 传统的开发模式下,Servlet处理用户的请求,找Dao查询数据,dao会创建与数据库之间的连接,完成数据查询后会关闭数据库的链接. 这样的方式会导致用户每 ...
- Python pygame安装过程笔记
今天看到一个教程,是关于Python安装pygame模块的.觉得很好,拿来分享一下. 安装Python 额,这个小题貌似在这里很是多余啊.但是为了照顾到刚刚学习Python的童鞋,我还是多啰嗦两句吧. ...
- 对LCS算法及其变种的初步研究
LCS的全称为Longest Common Subsequence,用于查找两个字符串中的最大公共子序列,这里需要注意区分子序列与子串,所谓子序列,指的是从前到后,可以跳跃元素筛选,而字串则必须连续筛 ...
- J2EE进阶(十三)Spring MVC常用的那些注解
Spring MVC常用的那些注解 前言 Spring从2.5版本开始在编程中引入注解,用户可以使用@RequestMapping, @RequestParam,@ModelAttribute等等这样 ...
- Cocos2D:塔防游戏制作之旅(十五)
Yes,貌似添加了好多的代码啊 ;] ,在你添加更多代码时,你可能注意到一些Xcode中的一些警告.首先你先忽略这些警告,我们先添加少量最终缺失的部分,然后再来解释上面代码做了什么! 在Enemy.m ...
- (一)php的基本知识和一些注意点
注意:任何程序,包括php,在运行时都在内存中进行,php代码需要被读取到内存中才能执行. [php的运行方式] 1.通过服务器(例如apache)调用. 2.通过命令行调用(不需要服务器参与,因为没 ...
- 数据从oracle转换到mysql
因为项目变更,需要把数据从oracle里转到mysql里. 第一个想法,自己写代码. 20分钟后,算了,还是找找工具吧. 第二步: 下了一个工具,二十分钟后,师兄发现,表的结构是倒完了,但是有的表数据 ...
- Java最最常用的100个类排序(非官方)
下面这句话是引用"大部分的 Java 软件开发都会使用到各种不同的库.近日我们从一万个开源的 Java 项目中进行分析,从中提取出最常用的 Java 类,这些类有来自于 Java 的标准库, ...