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中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
随机推荐
- Android实现系统下拉栏的消息提示——Notification
Android实现系统下拉栏的消息提示--Notification 系统默认样式 默认通知(通用) 效果图 按钮 <Button android:layout_width="match ...
- C语言实现简单黑客帝国代码流
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <windows.h> ...
- Android仿淘宝购物车demo
夏的热情渐渐退去,秋如期而至,丰收的季节,小编继续着实习之路,走着走着,就走到了购物车,逛过淘宝或者是京东的小伙伴都知道购物车里面的宝贝可不止一件,对于爱购物的姑娘来说,购物车里面的商品恐怕是爆满,添 ...
- iOS中 本地通知/本地通知详解 韩俊强的博客
布局如下:(重点讲本地通知) iOS开发者交流QQ群: 446310206 每日更新关注:http://weibo.com/hanjunqiang 新浪微博 Notification是智能手机应用编 ...
- 03 ImageView 图片
四 ImageView 父类 : view >概念:展示图片的控件 >属性: <!-- android:adjustViewBounds=&qu ...
- Java创建柱状图及饼状图
Java创建图表其实还是很方便的,但是要引入相关的jar包.如下 jfreechart.jar jcommon,jar gnujaxp.jar 其中最主要的是jfreechart.jar. 下面就让我 ...
- Java 中Log4j的使用详情
Log4j 真的很简单,简单到令人发指的地步.不是要记录日志吗?那就给你一个Log ,然后你用Log 来写东西就行了,先来一个完整类示例: package test; import org.apach ...
- 【一天一道LeetCode】#77. Combinations
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given t ...
- sublimeText3使用记录
sublime确实是神器,最近学习了一下,做个记录 1.下载 http://www.sublimetext.com/3 选择对应的版本安装即可(我的是win10 64位机) 2.个人配置 2.1.默认 ...
- 《15个提高Google搜索的技巧》
为了得到更加「多元化」的搜索结果,虽然 Google 目前访问起来并不是那么方便,但是仍然有很多人把它作为常用搜索引擎在使用. 其实除了最简单的关键词搜索之外,搜索引擎还提供了很多精细化的搜索功能,如 ...