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,流水线就可以看做是责任链模式的体现,工人就是链条上的一员,有的工人组装屏幕,有的工人检查手机,有的工人进行手机的包装等,下面我们就以代码的方式实现:

苹果手机类:

Java代码  
  1. package com.lifanghu.chain;
  2. /**
  3. * @author lifh
  4. * @mail wslfh2005@163.com
  5. * @since 2012-6-12 下午11:20:18
  6. * @name com.lifanghu.chain.Iphone.java
  7. * @version 1.0
  8. */
  9. public class Iphone {
  10. private String state = "我是一台苹果机器;";
  11. public String getState() {
  12. return state;
  13. }
  14. public void setState(String state) {
  15. this.state = state;
  16. }
  17. }

抽象处理接口类:

Java代码  
  1. package com.lifanghu.chain;
  2. /**
  3. * @author  lifh
  4. * @mail    wslfh2005@163.com
  5. * @since   2012-6-12 下午11:23:36
  6. * @name    com.lifanghu.chain.IWorker.java
  7. * @version 1.0
  8. */
  9. public interface IWorker {
  10. /**
  11. * 处理方法
  12. * @param iphone
  13. * @author lifh
  14. */
  15. void handleIphone(Iphone iphone);
  16. /**
  17. * 设置下一个处理者
  18. * @param worker
  19. * @author lifh
  20. */
  21. void setNext(IWorker worker);
  22. }

具体处理者:

Java代码  
  1. package com.lifanghu.chain;
  2. /**
  3. * @author lifh
  4. * @mail wslfh2005@163.com
  5. * @since 2012-6-12 下午11:29:46
  6. * @name com.lifanghu.chain.Worker1.java
  7. * @version 1.0
  8. */
  9. public class Worker1 implements IWorker {
  10. private IWorker next;
  11. public void handleIphone(Iphone iphone) {
  12. iphone.setState(iphone.getState() + "我被装了一个黑色的后盖;");
  13. if (next != null)
  14. next.handleIphone(iphone);
  15. }
  16. public void setNext(IWorker worker) {
  17. this.next = worker;
  18. }
  19. }
  20. package com.lifanghu.chain;
  21. /**
  22. * @author lifh
  23. * @mail wslfh2005@163.com
  24. * @since 2012-6-12 下午11:34:32
  25. * @name com.lifanghu.chain.Worker2.java
  26. * @version 1.0
  27. */
  28. public class Worker2 implements IWorker {
  29. private IWorker next;
  30. public void handleIphone(Iphone iphone) {
  31. iphone.setState(iphone.getState() + "我被装了一块电池;");
  32. if (next != null)
  33. next.handleIphone(iphone);
  34. }
  35. public void setNext(IWorker worker) {
  36. this.next = worker;
  37. }
  38. }
  39. package com.lifanghu.chain;
  40. /**
  41. * @author lifh
  42. * @mail wslfh2005@163.com
  43. * @since 2012-6-12 下午11:34:32
  44. * @name com.lifanghu.chain.Worker3.java
  45. * @version 1.0
  46. */
  47. public class Worker3 implements IWorker {
  48. private IWorker next;
  49. public void handleIphone(Iphone iphone) {
  50. iphone.setState(iphone.getState() + "我现在是一台完整的Iphone了。");
  51. if (next != null)
  52. next.handleIphone(iphone);
  53. }
  54. public void setNext(IWorker worker) {
  55. this.next = worker;
  56. }
  57. }

客户端调用者:

Java代码  
  1. package com.lifanghu.chain;
  2. /**
  3. * @author lifh
  4. * @mail wslfh2005@163.com
  5. * @since 2012-6-12 下午11:37:27
  6. * @name com.lifanghu.chain.Client.java
  7. * @version 1.0
  8. */
  9. public class Client {
  10. public static void main(String[] args) {
  11. IWorker worker1 = new Worker1();
  12. IWorker worker2 = new Worker2();
  13. IWorker worker3 = new Worker3();
  14. worker1.setNext(worker2);
  15. worker2.setNext(worker3);
  16. Iphone iphone = new Iphone();
  17. worker1.handleIphone(iphone);
  18. System.out.println(iphone.getState());
  19. }
  20. }

输出结果:

 写道
我是一台苹果机器;我被装了一个黑色的后盖;我被装了一块电池;我现在是一台完整的Iphone了。

好了,现在一台苹果就组装完成了,发现了没有,我们的代码比较整洁清新,没有大量的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的实现:

Java代码  
  1. //消息接收到以后NextFilter的实现会把消息传递给nextEntry去处理。
  2. public void messageReceived(IoSession session, Object message) {
  3. Entry nextEntry = EntryImpl.this.nextEntry;
  4. callNextMessageReceived(nextEntry, session, message);
  5. }

DefaultIoFilterChain再将消息传递给本Filter的messageReceived方法进行实际的消息接收处理工作:

Java代码  
  1. private void callNextMessageReceived(Entry entry, IoSession session,
  2. Object message) {
  3. try {
  4. IoFilter filter = entry.getFilter();
  5. NextFilter nextFilter = entry.getNextFilter();
  6. //本过滤器进行数据处理,完成后再把消息传向下个过滤器
  7. filter.messageReceived(nextFilter, session,
  8. message);
  9. } catch (Throwable e) {
  10. fireExceptionCaught(e);
  11. }
  12. }

当消息处理完成以后,消息就要进入到业务处理IoHandler的实现类中去完成业务的相关操作了。这可以在链尾看到相关业务传递:

Java代码  
  1. @Override
  2. public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
  3. AbstractIoSession s = (AbstractIoSession) session;
  4. if (!(message instanceof IoBuffer)) {
  5. s.increaseReadMessages(System.currentTimeMillis());
  6. } else if (!((IoBuffer) message).hasRemaining()) {
  7. s.increaseReadMessages(System.currentTimeMillis());
  8. }
  9. try {
  10. // 最后一个filter会进入到handler进行消息处理。
  11. session.getHandler().messageReceived(s, message);
  12. } finally {
  13. if (s.getConfig().isUseReadOperation()) {
  14. s.offerReadFuture(message);
  15. }
  16. }
  17. }

至此,Mina的链表结构就基本讲完了,其实仔细看看它的代码还是比较容易理解的,可能里面有些细节还需要我们去琢磨。

链表建立了以后,外界是怎样调用的呢?

在org.apache.mina.core.filterchain包下我们可以看到类IoFilterEvent,可以看到它实现了基于事件的处理模型,当一个事件(比如接收到消息)发生后会触发相应的事件,进而调用过滤器链的消息处理功能进行消息的处理和转发,这块其实会有线程池的参与完成,会在以后的文章中说明这块。

Java代码  
  1. public void fire() {
  2. IoSession session = getSession();
  3. NextFilter nextFilter = getNextFilter();
  4. IoEventType type = getType();
  5. if (DEBUG) {
  6. LOGGER.debug( "Firing a {} event for session {}",type, session.getId() );
  7. }
  8. switch (type) {
  9. case MESSAGE_RECEIVED:
  10. //触发消息接收
  11. Object parameter = getParameter();
  12. nextFilter.messageReceived(session, parameter);
  13. break;

当然也可以直接调用:

Java代码  
  1. //触发过滤器的接收消息处理
  2. session.getFilterChain().fireMessageReceived(newBuf);

还有一个类DefaultIoFilterChainBuilder,它以用户更易用的角度完成了对过滤器链的封装操作,这里就不细讲了。

总结:本文章主要讲了责任链模式在Mina中的实现,做为一个优秀的框架我们没理由不好好去学习。

每天进步一点点,不做无为的码农。。。。。

2012年6月13日星期三

码农虎虎

http://weibo.com/hurtigf

http://www.lifanghu.com/

wslfh2005@163.com

深入解析Apache Mina源码(1)——Mina的过滤器机制实现的更多相关文章

  1. NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信

    1.NIO超级陷阱 之所以说NIO超级陷阱,就是因为我在本系列开头的那句话,因为使用缺陷导致客户业务系统瘫痪.当然,我对这个问题进行了很深的追踪,包括对MINA源码的深入了解,但其实之所以会出现这个问 ...

  2. Mina源码阅读笔记(七)—Mina的拦截器FilterChain

    Filter我们很熟悉,在Mina中,filter chain的用法也类似于Servlet的filters,这种拦截器的设计思想能够狠轻松的帮助我们实现对资源的统一处理.我们先大致连接下mina中的f ...

  3. Mina源码阅读笔记(四)—Mina的连接IoConnector2

    接着Mina源码阅读笔记(四)-Mina的连接IoConnector1,,我们继续: AbstractIoAcceptor: 001 package org.apache.mina.core.rewr ...

  4. Mina源码阅读笔记(一)-整体解读

    今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...

  5. apache flink源码挖坑 (未完待续)

    Apache Flink 源码解读(一) ​ By yyz940922原创 项目模块 (除去.git, .github, .idea, docs等): flink-annotations: flink ...

  6. 详细解析Thinkphp5.1源码执行入口文件index.php运行过程

    详细解析Thinkphp5.1源码执行入口文件index.php运行过程 运行了public目录下的index.php文件后,tp的运行整个运行过程的解析 入口文件index.php代码如下: < ...

  7. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  8. 《Apache Spark源码剖析》

    Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...

  9. Apache Kafka源码分析 – Broker Server

    1. Kafka.scala 在Kafka的main入口中startup KafkaServerStartable, 而KafkaServerStartable这是对KafkaServer的封装 1: ...

  10. rest_framework解析器组件源码流程

    rest_framework解析器组件源码流程 解析器顾名思义就是对请求体进行解析.为什么要有解析器?原因很简单,当后台和前端进行交互的时候数据类型不一定都是表单数据或者json,当然也有其他类型的数 ...

随机推荐

  1. c程序设计语言 by K&R(二)指针与数组

    指针与数组 1. c语言只有值传递,没有引用传递 可通过指针交换 #include <stdio.h> #include <stdlib.h> void swap(int* a ...

  2. ST-SSL: 用于交通流量预测的时空自监督学习《Spatio-Temporal Self-Supervised Learning for Traffic Flow Prediction》(交通流量预测、时空异质性、自监督、数据增强)

    2023年10月23日,继续论文,好困,想发疯. 论文:Spatio-Temporal Self-Supervised Learning for Traffic Flow Prediction Git ...

  3. 使用 Performance API 实现前端资源监控

    1. Performance API 的用处 Performance API 是浏览器中内置的一组工具,用于测量和记录页面加载和执行过程中的各类性能指标.它的主要用处包括: 监控页面资源加载:跟踪页面 ...

  4. MVC模式与三层架构

    MVC 模式    三层架构    MVC 模式 与 三层架构 的关系   

  5. 文件包含与PHP伪协议

    文件包含与伪协议 一.无任何过滤措施的文件包含漏洞:(ctfshow-web78): 1.data://协议: ?file=data://text/plain,<?php system('tac ...

  6. WiFi基础(五):802.11帧结构与WiFi控制帧、管理帧、数据帧

    liwen01 2024.09.22 前言 前面介绍了 WiFi 的工作原理和 WiFi 的接入过程,这里将通过分析 WiFi 具体数据包结构,让你对 WiFi 工作原理和接入过程有一个更进一步的了解 ...

  7. iOS关于列表布局的几种实现方式小结

    最近在项目开发中,遇到了常见的列表布局样式,功能的要求是最多六行,动态展示.当时想到的方案是,抽象出一个cell,初始化六个标签,动态的控制显示和隐藏,这样功能上没有问题,就是代码有些冗余.请教了身边 ...

  8. LINQ 统计字符频率

    var arr = new string[] {"test","zhulongxu","asdfdgd","yangmi" ...

  9. 推荐一款开源的API开放平台,5分钟就可以搭建企业专属的API开放门户!

    前言 在过去的十年中,企业API治理并未受到广泛关注.然而,随着时间的推进,特别是在近几年,企业技术管理者对API治理的重视程度显著提高,开始将API视为企业资产的重要组成部分.API不再仅仅是技术层 ...

  10. 华为云-容器引擎CCE-基本概念

    云容器引擎(Cloud Container Engine,简称CCE)提供高度可扩展的.高性能的企业级Kubernetes集群,支持运行Docker容器.借助云容器引擎,您可以在华为云上轻松部署.管理 ...