IoService通过构造函数的形式成为了IoSession一部分,IoSession是通过IoAcceptor以及connector创建出来,这二者其实就是IoService,所以对于IoSession的模式就是蝎子模式,我创建了你,然后,我成为了你的一部分(蝎子生完了孩子,将会被孩子吃掉);IoSession一切核心内容比如Handler,FilterChain(当然还有Filter)都是来自于IoService(它的创建者,可能是Acceptor,也可能是IoConnector);代码实现层面上也是首先是创建服务,然后是为服务(容器)指定属性(Handler、Filter),最后通过服务来创建IoSession;

作为服务系,除了IoAcceptor以及Connector之外,还有一个很重要的类:AbstractorIoService,这个抽象类最大的贡献在于承担了底层执行的功用,它包含了一个Executor对象,Executor在java中是对于进程的抽象,Executor本质就是底层执行任务;对于Executor的来源也是有两个,一个是通过构造参数的形式传入,另外一种方式是通过Executors.newCachedThreadPool()来获得;

Polling系就是实现了基于NIO的"园丁模式"来进行的,AbstractorPollingIoAcceptor关联了一个IoProcessor,这个processor里面封装了针对IoSession所有的核心操作:添加(add,向内部维护的列表中添加新的Session),写(flush(),向session中写入内容),写入缓存(write(),并没有真正的写入,只是写入future)以及移除(remove,移除session);Processor的来源有两个,一个是通过构造参数传递过来,另外,则是通过SimpleIoProcessorPool进行构建;对于前者,是基于NIO的模式;对于后者,只有非NIO实现的情况才会使用SimpleIoProcessorPool;从MINA官方文档的Demo来看,几乎看不到非NIO的例子;既然基于JDK1.4的NIO已经非常成熟,为什么不用呢?ProcessorPool是给那些JDK1.4之前的老爷车准备的吧?不过对于NIO的了解还是需要看一下《Java NIO》才会有比较深入的了解;

上图揭示了两个重要的方面:第一个是作为Polling系中的Acceptor,里面实现一个很核心的东东,内部实现类Acceptor,这个类继承自runnable接口,实现多线程的两种机制之一(另外一种是直接继承自Thread)。Acceptor里面做了很多重要的事情,下面我们将会介绍到;

另外一个就是NioAcceptor在使用的时候用到了三个核心对象:Filter/FilterChainBuilder、Handler以及binding时需要的Address(地址以及端口)三大巨头对象;

 

 

NioXX都是基于NIO的Selector的"园丁-草莓园"模式来进行的;所以NioXX里面都会关联一个selector;connect()方法将会调用到newSession()方法,这个方法将会常见NIO系的一个Channel,Channel就代表一条交流的通道,你可以理解为创建条电话线,用于电话两端的对象进行交流;

NioConnector的connet方法将会委托到PollConnetor里面的connect0方法,这个方法里面将会创建一个IoSession,这个IoSession的创建就是蝎子模式,一方面它的构造参数是创建者(Creator)的Channel以及Processor,同时还有创建者本身;

Acceptor以及Connector其实本质是一个封装类,他们封装了IoService以及IoProcessor,一个是服务,一个是操作执行;前者通过继承的放置,后者通过聚合的方式,对于IoService而言,也是封装这,它封装了(包容了)Config,FilterChain(Filter)以及IoHandler;

SimpleProcessorPool的内部构造如图所示,但是对于NIO当道,使用simpleProcessorPool的机会不会很多吧;

上面张图主要是揭示了Executor和Processor之间的关系;介绍他们的关系之前首先看一下Processor和AbstractPollingIoProcessor干系;Polling系列模式都是如此,会有一个内部类,他们大部分操作都是基于"队列"的,比如PollingProcessor中就有flushingSessions,newSessions等队列,写操作、创建Session的操作都是先放到队列中;然后调用wakeup(),wakeup就相当于是一个通知施工队(Processor):开工了;之前的施工队可能一直在等待:

int selected = select(SELECT_TIMEOUT);

wakeup就是告诉select立即返回,如果没有select,那么当执行完for语句一个循环,再进行新的select的时候也会立即返回;这样对于一些重要的操作比如创建Session之类的,就可以马上得到执行(但是也是要首先放到newSessions队列中,但是可以放入队列后不久就处理);

上面介绍的是Polling系的操作原理:基于队列以及selector的wakeup通知;

在MINA还是用了Java的多线程:Executor;之前Polling机制有一个问题:如何来执行监听?Processor继承了Runnable,这意味着可以通过Executor(线程封装类)来进行启动;startupProcessor方法的实现对此有详实的诠释;

并不是所有的调用都会调用到executor.execute,只是第一次执行Processor的时候需要如此,compareAndSet的意思就是当第二个参数和第一个参数一致的时候,才会有分支的内容;

NioSession类比较简单,里面关于IoProcessor只是实现了封装,提供了getProcessor()方法,这是因为所有的核心操作都封装在了他的基类AbstractIoSession中;对于属相修改相关的方法,比如suspendRead/suspendWrite这些牵涉到修改session属性(比如suspendRead就是牵涉到writeSuspended的修改)会通过调用下面的方法通知IoProcessor

Processor和IoProcessor是不同的概念,前者是一个后者的一个内部类,用于执行操作;后者则是一个封装类,封装了一些操作,供Processor调用;

Processor里面处理所有的核心针对session的操作,创建,销毁,读写,里面的process方法进一步调用了read(),read方法将会触发messageReceived事件,至此,和之前成天打交道的messageReceived事件终于关联上了;

在创建Connector赋值的时候,需要为他指定FilterChain以及Handler;conn()方法返回的是ConnectFuture;MINA的核心操作都是基于非阻塞的模式,方法调用后立即返回,如果你需要监听处理返回结果,那么就需要接受Future系的东西;调用conn()方法将会返回接口ConnectFuture,通过调用awaitUninterruptibly()方法,来进行阻塞当前进程(或者另一起一个进程来对Future进行阻塞);

MINA里面实现这种机制是这样,Future系都是继承自DefaultIoFuture,在DefaultIoFuture中有两个核心方法,一个是awaitUninterruptibly()方法,用于加锁,创建等待队列,下图代码是在await0()方法(由awaitUninterruptibly方法调用):

第二个核心方法是setValue,在这个方法中用于通知等待队列中竞争下一个锁;

setValue这个方法就被广大继承类们根据自己的需要设定时间点进行调用;比如对于DefaultWriteFuture而言,有一个setWritten(),就是内部调用setValue,进行释放锁;

DefaultWriteFuture的setWritten()是在write操作放到WriteQueue后,从队列中Poll出来并被flush之后,调用的(即写操作完成后);

对于DefaultConnectionFuture而言,setValue是被setSession所封装,触发的时间点是创建session成功后(MINA底层的封装的NIO技术的Selector感知到有OP_CONNECT的时候将会调用返回创建Session成功;

MINA的过滤器机制符合装箱-拆箱模式;这种模式意味着,客户端以及服务器端必须要有正向-逆向匹配的机制;比如如果客户端是直接使用socket进行通信,而且没有编码;那服务器端就应该是没有设置CodecFilter的过滤器;但是如果服务器端有添加CodecFilter过滤器,那么客户端最好也是用MINA,同时添加CodecFilter进行编码;这样,服务器端获取到数据后,进行解码后才能够获得准确的原始信息;或者客户端使用原生的Socket进行通信,那么必须要对消息内容进行编码,而且编码规则要保证和MINA的编码器规则是一样的,以保证服务器解码成功;

 

 

 

 

 

MINA源码分析的更多相关文章

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

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

  2. Dubbo 源码分析 - 服务导出

    1.服务导出过程 本篇文章,我们来研究一下 Dubbo 导出服务的过程.Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可 ...

  3. AndroidPn源码分析(二)

    接上篇: (一)客户端与服务器建立连接 上一篇写到ClientSession createClientSession这里,创建一个客户端的session.在SessionManager类中创建了ses ...

  4. JVM源码分析之堆外内存完全解读

    JVM源码分析之堆外内存完全解读   寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...

  5. 🏆【Alibaba微服务技术系列】「Dubbo3.0技术专题」回顾Dubbo2.x的技术原理和功能实现及源码分析(温故而知新)

    RPC服务 什么叫RPC? RPC[Remote Procedure Call]是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范.它允许程序调用另一个地址空间(通常是共享网络的另 ...

  6. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  7. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  8. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  9. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

随机推荐

  1. Android用悬浮按钮实现翻页效果

    今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在An ...

  2. TCP/IP协议原理与应用笔记16:交换机和路由器区别

    1.交换机和路由器区别 (1)交换机:     交换机是一种基于MAC(网卡的硬件地址)识别,能完成封装转发数据包功能的网络设备.交换机可以“学习”MAC地址,并把其存放在内部地址表中,通过在数据帧的 ...

  3. iOS之AlertController的使用

    iOS 8的新特性之一就是让接口更有适应性.更灵活,因此许多视图控制器的实现方式发生了巨大的变化.全新的UIPresentationController 在实现视图控制器间的过渡动画效果和自适应设备尺 ...

  4. verilog 数组参数

    verilog 支持定义数组参数,这样工程很大时,例化模块时可以使代码更简洁:详见实例 module dma_controller #( parameter integer C0_MAX_MIG_BL ...

  5. 【转】小议Bug敏感度---Bug敏感度的故事(一)

    在测试圈中,相信大家对“Bug敏感度”这一词并不陌生,但是Bug敏感度具体是指什么呢,本文对此关键词进行解读的基础上,对其与软件质量的关系,影响的关键因素,如何提高测试人员的bug敏感度进行分享.(- ...

  6. C#测量程序运行时间及cpu使用时间

    转载:http://www.cnblogs.com/yanpeng/archive/2008/10/15/1943369.html 对一个服务器程序想统计每秒可以处理多少数据包,要如何做?答案是用处理 ...

  7. 获取汉字拼音 Java

    两种方法:一个是使用btye数组,一个是引入jar包进行操作. 1. public class CharacterParser { private static int[] pyvalue = new ...

  8. Java 泛型类型的一些限制

    由于泛型类型在运行时被消除,因此,对于如何使用泛型类型是有一些限制的. 限制1:不能使用new E() 不能使用泛型类型参数创建实例.例如,下面的语句是错误的: E object = new E(); ...

  9. iOS中RGB颜色转换

    iOS中RGB常用的色值,同时可将对颜色的设置定义成宏,方便开发应用,如: // RGB颜色转换(16进制->10进制) #define UIColorFromRGB(rgbValue) [UI ...

  10. cocoa pods

    # cocoa pods * `CocoaPods` 是 iOS 最常用最有名的类库管理工具 * 作为 iOS 程序员,掌握 `CocoaPods` 的使用是必不可少的基本技能 ## pod 命令汇总 ...