深入解析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,当然也有其他类型的数 ...
随机推荐
- 【YashanDB知识库】表收集统计信息默认阈值引起SQL执行效率差
[问题分类]性能优化 [关键字]统计信息,阈值,执行计划 [问题描述]表新增87w数据自动收集统计信息任务没有启动导致SQL执行计划变差 [问题原因分析] CUS_REGISTER_READ 数据总量 ...
- 深入理解Argo CD工作原理
1. ArgoCD 的架构 ArgoCD 是一个 Kubernetes 原生的持续交付工具,它通过监控 Git 仓库中的应用定义来自动部署应用到 Kubernetes 集群.其核心架构由以下几个关键组 ...
- 【SpringBoot Demo】MySQL + JPA + Hibernate + Springboot + Maven Demo
主要包含:springboot+jpa+hibernate+mysql+lombok (两年前写过一个,现在重新记录一个) 1. 目录结构: 2. pom 文件 1 <?xml version= ...
- HTML – script async defer
参考 Youtube – #3 JavaScript Loading Strategies (async and defer) | JavaScript Full Tutorial no async ...
- 使用 Flutter 3.19 更高效地开发
我们已隆重推出全新的 Flutter 版本--Flutter 3.19.此版本引入了专为 Gemini 设计的新 Dart SDK.一个能让开发者对 Widget 动画实现精细化控制的全新 Widge ...
- .NET 8.0 酒店管理系统设计与实现
前言 给大家推荐一个基于.NET 8.0 的中小型酒店设计的管理系统. 随着酒店的日常工作增加,很难用人工去进行处理一些繁琐的数据,也可能会因为人工的失误而造成酒店的损失,因此需要一款可以协助酒店进行 ...
- linux下UsbMon-WireShark之USB协议抓取分析
usbmon配置 使用usbmon抓包分的,是需要 内核开启CONFIG_USB_MON=m, 重新编译内核, 编译ko : make ARCH=arm64 CROSS_COMPILE=aarch64 ...
- 最受DBA欢迎的数据库技术文档-巡检篇
有人说,"数据库巡检是数据库运维领域最重要的工作".的确,为了保证数据库的稳定.安全运行,除了可以对数据库进行监控以及时知晓故障苗头,定期的"健康体检"则尤为重 ...
- PostgreSQL 15 新特性解读 | 墨天轮优质文章合集
5月19日,PostgreSQL 全球开发组宣布 PostgreSQL 15 的第一个 beta 版本,这一新版本在开发者体验.性能表现等方面都有提升.为了帮助大家更快速了解到PostgreSQL 1 ...
- element-admin - 图片上传组件 ImageUpload
预览详情 : 父组件:注册引入子组件 :只需要传递一个数据 limit :这是限制显示多少张图片 : 子组件: - 图片上传 - el-upload 代码 : <template> & ...