深入解析Apache Mina源码(1)——Mina的过滤器机制实现
1、深入解析Apache Mina源码(1)——Mina的过滤器机制实现
2、深入解析Apache Mina源码(2)——Mina的事件模型
3、深入解析Apache Mina源码(3)——Mina的线程池模型
4、深入解析Apache Mina源码(4)——Mina编解码以及对粘包和断包的处理
一、责任链模式的本来面目
Mina 中有一个重要的设计模式-责任链模式,它将此模式成功的应用在了它的过滤器链(IoFilterChain)中。开发过J2EE的童鞋们应该对这个模式比较清楚,在Servlet中我们就可以加入Filter的实现,还有Hibernate中也实现了FilterChain。学习怎么实现责任链模式对于我们对开源软件的学习和以后的工作都会有莫大的帮助。
我们知道计算机系统就是接收信息,进行信息处理,信息输出的过程,那么在这个过程中我们加入过滤器有很多好处,消息经过特定功能的多个过滤器进行逐步处理得到所需要的最终信息,让处理过程透明,责任明晰,方便扩展。
责任链模式的定义我也就不说了,网上一大堆,我的理解是可以把它理解成一个有向链表,消息在这个链表中的某个过滤器进行处理然后再传向下个过滤器,在每个过滤器中都可以处理这些消息,也可以不处理。如图:

责任链模式的类图如下:

其实这里面最核心的就是Handler了,它可是是一个接口或者是一个抽象类,它有对自己的一个引用successor,然后有个处理方法HandleRequest()。因为有了对自己的引用successor所以当本对象不能处理的时候可以转向successor.HandleRequest()方法,这样一个“链”就形成了。
你应该挺羡慕富士.康里面生产苹果手机的工人吧,你平时最喜欢的苹果手机就是他们生产出来的,他们一个人就能把苹果手机生产出来吗?不是的,他们是流水线做业的,OK,流水线就可以看做是责任链模式的体现,工人就是链条上的一员,有的工人组装屏幕,有的工人检查手机,有的工人进行手机的包装等,下面我们就以代码的方式实现:
苹果手机类:
- package com.lifanghu.chain;
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-12 下午11:20:18
- * @name com.lifanghu.chain.Iphone.java
- * @version 1.0
- */
- public class Iphone {
- private String state = "我是一台苹果机器;";
- public String getState() {
- return state;
- }
- public void setState(String state) {
- this.state = state;
- }
- }
抽象处理接口类:
- package com.lifanghu.chain;
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-12 下午11:23:36
- * @name com.lifanghu.chain.IWorker.java
- * @version 1.0
- */
- public interface IWorker {
- /**
- * 处理方法
- * @param iphone
- * @author lifh
- */
- void handleIphone(Iphone iphone);
- /**
- * 设置下一个处理者
- * @param worker
- * @author lifh
- */
- void setNext(IWorker worker);
- }
具体处理者:
- package com.lifanghu.chain;
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-12 下午11:29:46
- * @name com.lifanghu.chain.Worker1.java
- * @version 1.0
- */
- public class Worker1 implements IWorker {
- private IWorker next;
- public void handleIphone(Iphone iphone) {
- iphone.setState(iphone.getState() + "我被装了一个黑色的后盖;");
- if (next != null)
- next.handleIphone(iphone);
- }
- public void setNext(IWorker worker) {
- this.next = worker;
- }
- }
- package com.lifanghu.chain;
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-12 下午11:34:32
- * @name com.lifanghu.chain.Worker2.java
- * @version 1.0
- */
- public class Worker2 implements IWorker {
- private IWorker next;
- public void handleIphone(Iphone iphone) {
- iphone.setState(iphone.getState() + "我被装了一块电池;");
- if (next != null)
- next.handleIphone(iphone);
- }
- public void setNext(IWorker worker) {
- this.next = worker;
- }
- }
- package com.lifanghu.chain;
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-12 下午11:34:32
- * @name com.lifanghu.chain.Worker3.java
- * @version 1.0
- */
- public class Worker3 implements IWorker {
- private IWorker next;
- public void handleIphone(Iphone iphone) {
- iphone.setState(iphone.getState() + "我现在是一台完整的Iphone了。");
- if (next != null)
- next.handleIphone(iphone);
- }
- public void setNext(IWorker worker) {
- this.next = worker;
- }
- }
客户端调用者:
- package com.lifanghu.chain;
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-12 下午11:37:27
- * @name com.lifanghu.chain.Client.java
- * @version 1.0
- */
- public class Client {
- public static void main(String[] args) {
- IWorker worker1 = new Worker1();
- IWorker worker2 = new Worker2();
- IWorker worker3 = new Worker3();
- worker1.setNext(worker2);
- worker2.setNext(worker3);
- Iphone iphone = new Iphone();
- worker1.handleIphone(iphone);
- System.out.println(iphone.getState());
- }
- }
输出结果:
好了,现在一台苹果就组装完成了,发现了没有,我们的代码比较整洁清新,没有大量的if/else语句,责任清晰明了,调用简单,想要扩展的话只需要再实现IWorker接口即可,这就是使用责任链模式的好处。
二、Mina是怎么实现责任链模式的
上面介绍了纯净的责任链模式,但是在真实的项目中写代码不可能完全照搬,所以多看看开源项目的代码写作方式也许才能真正提高我们的编程能力。就以Mina的过滤器链来看,对这种模式进行了自己的实现,但是道理是相通的,带着责任链模式的理解去看看Mina的实现是怎样的。
先看一下Mina过滤器的类图结构:

从图中我们可以看出Mina对于此模式的实现是相对比较复杂的,其实从它的代码上也可以看出来,当时也是花了好大力气才把它这块看明白,其实主要在于理清思路,抓住核心类,最主要的一个接口IoFilterChain和它的一个内部接口Entry,其中IoFilterChain代表了过滤器的容器,它本身就是一个对象引用形成的链表结构,默认的实现DefaultIoFilterChain其实有对链表头(head)的引用,找到头后就可以顺着头向下找,一直找到尾(tail),Entry是对IoFilter和NextFilter的封装整合接口,它属于链表IoFilterChain中的元素。指向当前和下一个过滤器。

EntryImpl 类中包含两个接口,filter和nextFilter,他们所用的接口是不一样的,至于为什么不用同一个接口,我想可能是因为接口职责单一的原则吧。

虽然有IoFilter和NextFilter两个接口,接口方法都差不多,但最后真正业务的执行者还是IoFilter的实现,IoFilterAdapter做为它的默认实现,完成了适配器的功能,以后的类可以直接继承它而不用实现IoFilter接口,想实现哪个方法只需要覆盖IoFilterAdapter的类的方法即可。NextFilter只起到转发的作用,如消息接收处理方法(messageReceived):
NextFilter的实现:
- //消息接收到以后NextFilter的实现会把消息传递给nextEntry去处理。
- public void messageReceived(IoSession session, Object message) {
- Entry nextEntry = EntryImpl.this.nextEntry;
- callNextMessageReceived(nextEntry, session, message);
- }
DefaultIoFilterChain再将消息传递给本Filter的messageReceived方法进行实际的消息接收处理工作:
- private void callNextMessageReceived(Entry entry, IoSession session,
- Object message) {
- try {
- IoFilter filter = entry.getFilter();
- NextFilter nextFilter = entry.getNextFilter();
- //本过滤器进行数据处理,完成后再把消息传向下个过滤器
- filter.messageReceived(nextFilter, session,
- message);
- } catch (Throwable e) {
- fireExceptionCaught(e);
- }
- }
当消息处理完成以后,消息就要进入到业务处理IoHandler的实现类中去完成业务的相关操作了。这可以在链尾看到相关业务传递:
- @Override
- 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 {
- // 最后一个filter会进入到handler进行消息处理。
- session.getHandler().messageReceived(s, message);
- } finally {
- if (s.getConfig().isUseReadOperation()) {
- s.offerReadFuture(message);
- }
- }
- }
至此,Mina的链表结构就基本讲完了,其实仔细看看它的代码还是比较容易理解的,可能里面有些细节还需要我们去琢磨。
链表建立了以后,外界是怎样调用的呢?
在org.apache.mina.core.filterchain包下我们可以看到类IoFilterEvent,可以看到它实现了基于事件的处理模型,当一个事件(比如接收到消息)发生后会触发相应的事件,进而调用过滤器链的消息处理功能进行消息的处理和转发,这块其实会有线程池的参与完成,会在以后的文章中说明这块。
- public void fire() {
- IoSession session = getSession();
- NextFilter nextFilter = getNextFilter();
- IoEventType type = getType();
- if (DEBUG) {
- LOGGER.debug( "Firing a {} event for session {}",type, session.getId() );
- }
- switch (type) {
- case MESSAGE_RECEIVED:
- //触发消息接收
- Object parameter = getParameter();
- nextFilter.messageReceived(session, parameter);
- break;
当然也可以直接调用:
- //触发过滤器的接收消息处理
- session.getFilterChain().fireMessageReceived(newBuf);
还有一个类DefaultIoFilterChainBuilder,它以用户更易用的角度完成了对过滤器链的封装操作,这里就不细讲了。
总结:本文章主要讲了责任链模式在Mina中的实现,做为一个优秀的框架我们没理由不好好去学习。
每天进步一点点,不做无为的码农。。。。。
2012年6月13日星期三
码农虎虎
wslfh2005@163.com
- 01_HandlerChain.rar (7.5 KB)
- 下载次数: 107
深入解析Apache Mina源码(1)——Mina的过滤器机制实现的更多相关文章
- NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信
1.NIO超级陷阱 之所以说NIO超级陷阱,就是因为我在本系列开头的那句话,因为使用缺陷导致客户业务系统瘫痪.当然,我对这个问题进行了很深的追踪,包括对MINA源码的深入了解,但其实之所以会出现这个问 ...
- Mina源码阅读笔记(七)—Mina的拦截器FilterChain
Filter我们很熟悉,在Mina中,filter chain的用法也类似于Servlet的filters,这种拦截器的设计思想能够狠轻松的帮助我们实现对资源的统一处理.我们先大致连接下mina中的f ...
- Mina源码阅读笔记(四)—Mina的连接IoConnector2
接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...
- Mina源码阅读笔记(一)-整体解读
今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...
- apache flink源码挖坑 (未完待续)
Apache Flink 源码解读(一) By yyz940922原创 项目模块 (除去.git, .github, .idea, docs等): flink-annotations: flink ...
- 详细解析Thinkphp5.1源码执行入口文件index.php运行过程
详细解析Thinkphp5.1源码执行入口文件index.php运行过程 运行了public目录下的index.php文件后,tp的运行整个运行过程的解析 入口文件index.php代码如下: < ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- 《Apache Spark源码剖析》
Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...
- Apache Kafka源码分析 – Broker Server
1. Kafka.scala 在Kafka的main入口中startup KafkaServerStartable, 而KafkaServerStartable这是对KafkaServer的封装 1: ...
- rest_framework解析器组件源码流程
rest_framework解析器组件源码流程 解析器顾名思义就是对请求体进行解析.为什么要有解析器?原因很简单,当后台和前端进行交互的时候数据类型不一定都是表单数据或者json,当然也有其他类型的数 ...
随机推荐
- SciPy从入门到放弃
目录 SciPy简介 拟合与优化模块 求最小值 曲线拟合 线性代数模块 统计模块 直方图和概率密度函数 统计检验 SciPy简介 SciPy是一种以NumPy为基础,用于数学.工程及许多其他的科学任务 ...
- 【YashanDB知识库】生成迁移报告失败,"报错未知类型错误异常:"
[标题]YMP迁移 [问题分类]迁移报告 [关键字]迁移报告.未知类型错误异常 [问题描述]下载迁移报告时报错"未知类型错误异常:",一长串英文 日志报错: [问题原因分析]jav ...
- JavaScript Library – Lit
前言 我写过一篇关于 Lit 的文章,Material Design, Angular Material, MDC, MWC, Lit 的关系. 如今 material-web MWC 已经发布 1. ...
- ASP.NET Core – TagHelper
前言 以前写的 Asp.net core 学习笔记之 Tag Helper, 这篇是整理版. 参考 Docs – Author Tag Helpers in ASP.NET Core Creating ...
- iPay88 学习笔记
ipay88 学习笔记 之前弄过 MOLPay 现在弄 ipay88</p><p>差不多的概念 这里记入流程就好了 首先是做订单, 然后通过 merchant key + 订单 ...
- Spring —— bean生命周期
bean生命周期 生命周期:从创建到消亡的完整过程 bean生命周期:bean从创建到销毁的整体过程 bean生命周期控制:在bean创建后到销毁前做一些事情 方式一:配置控制生命周期 <b ...
- 《TensorFlow+Keras自然语言处理实战》已出版
<TensorFlow+Keras自然语言处理实战>已出版 当当京东天猫均有出售.清华社官网信息如下: http://www.tup.tsinghua.edu.cn/booksCenter ...
- linux中透明巨页与巨页的区别
在Linux中,透明巨页(Transparent HugePage)和巨页(HugePage)是两种不同的内存管理技术. 透明巨页是Linux内核中的一项特性,旨在提高内存的利用率和性能.它通过将内存 ...
- 数列专题2 求数列的前n项和
\({\color{Red}{欢迎到学科网下载资料学习 }}\) [ [基础过关系列]高二数学同步精品讲义与分层练习(人教A版2019)] ( https://www.zxxk.com/docpack ...
- OpenGL和OpenCL区别
1.OpenGL用于图形渲染程序:OpenCL用于复杂的计算.他们都是由Khronos管理并使用C语言编译. 2.OpneGL使编程能够进行图形操作:OpenCL使编程能够在多个处理器中进行计算. 3 ...