MINA源码分析
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源码分析的更多相关文章
- Mina源码阅读笔记(一)-整体解读
今天的这一节,将从整体上对mina的源代码进行把握,网上已经有好多关于mina源码的阅读笔记,但好多都是列举了一下每个接口或者类的方法.我倒是想从mina源码的结构和功能上对这个框架进行剖析.源码的阅 ...
- Dubbo 源码分析 - 服务导出
1.服务导出过程 本篇文章,我们来研究一下 Dubbo 导出服务的过程.Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可 ...
- AndroidPn源码分析(二)
接上篇: (一)客户端与服务器建立连接 上一篇写到ClientSession createClientSession这里,创建一个客户端的session.在SessionManager类中创建了ses ...
- JVM源码分析之堆外内存完全解读
JVM源码分析之堆外内存完全解读 寒泉子 2016-01-15 17:26:16 浏览6837 评论0 阿里技术协会 摘要: 概述 广义的堆外内存 说到堆外内存,那大家肯定想到堆内内存,这也是我们 ...
- 🏆【Alibaba微服务技术系列】「Dubbo3.0技术专题」回顾Dubbo2.x的技术原理和功能实现及源码分析(温故而知新)
RPC服务 什么叫RPC? RPC[Remote Procedure Call]是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范.它允许程序调用另一个地址空间(通常是共享网络的另 ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
随机推荐
- $GLOBALS['HTTP_RAW_POST_DATA'] 和$_POST的区别(转)
---恢复内容开始--- $_POST:通过 HTTP POST 方法传递的变量组成的数组.是自动全局变量. $GLOBALS['HTTP_RAW_POST_DATA'] :总是产生 $HTTP_RA ...
- [原理][源代码解析]spring中@Transactional,Propagation.SUPPORTS,以及 Hibernate Session,以及jdbc Connection关系---转载
问题: 一. 1. Spring 如何处理propagation=Propagation.SUPPORTS? 2. Spring 何时生成HibernateSession ? 3. propagati ...
- Android应用程序所包含的四种组件和DDMS
关注用户组件 Activity 编辑文本 .玩游戏 后台进程 Service ...
- c#中[Flags] 枚举类型定义问题_百度知道
[Flags]的微软解释是“指示可以将枚举作为位域(即一组标志)处理.”其实就是在编写枚举类型时,上面附上Flags特性后,用该枚举变量是既可以象整数一样进行按位的“|”或者按位的“&”操作了 ...
- Python之路【第二十四篇】:Python学习路径及练手项目合集
Python学习路径及练手项目合集 Wayne Shi· 2 个月前 参照:https://zhuanlan.zhihu.com/p/23561159 更多文章欢迎关注专栏:学习编程. 本系列Py ...
- 结合Retrofit,RxJava,Okhttp,FastJson的网络框架RRO
Retrofit以其灵活的调用形式, 强大的扩展性著称. 随着RxAndroid的推出, Retrofit这样的可插拔式的网络框架因其可以灵活兼容各种数据解析器, 回调形式(主要还是RxJava啦)而 ...
- HeaderViewListAdapter cannot be cast to listAdapter问题原因及解决办法
[o] 在listView中添加leaderView 和footerView的时候要注意在setAdapter之前调用,不然会报如下异常: listAdapter cannot be cast to ...
- ASC码 .
有些时候需要用到一些字符的ASC码,到网上查找太麻烦,现在记录下来. 第128-255号为扩展字符(不常用) Dec Hx Oct Char Dec Hx Oct Char Dec Hx Oct ...
- 各种排序算法及c语言实现
插入排序O(n^2) 冒泡排序 O(n^2) 选择排序 O(n^2) 快速排序 O(n log n) 堆排序 O(n log n) 归并排序 O(n log n) 希尔排序 O(n^1.25) 1.插 ...
- TCP调试助手
网络开发经常要用到一些TCP&UDP的调试工具,搜集一些备用. 目前总结工具有(不分先后): chrome等自带调试器调试HTTP Fiddler(.NET)和Charles debugger ...