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 ...
随机推荐
- Android 接收短信
启动程序时启动一个service,在service里注册接收短信的广播,当手机收到短信里,打印出短信内容跟电话号码. package com.lmy.SmsListener; import andro ...
- 【转】GitHub删除一个仓库——2013-08-27 21
http://xiacijian.blog.163.com/blog/static/849931902012111195041170/ 1.进入要删除的仓库 2.找到 导航栏 Code NetWor ...
- PPPoE Server Under Ubuntu/Debian
http://imranasghar.blogspot.com/2009/05/pppoe-server-under-ubuntudebian.html ----------------------- ...
- SAXParser 解析器和 XMLEventReader(读取XML文档)
import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import java ...
- C#异常之(已有打开的与此 Command 相关联,已有打开的与此命令相关联的 DataReader,必须首先将它关闭。)
异常提示:“System.InvalidOperationException”类型的异常在 System.Data.dll 中发生,但未在用户代码中进行处理 其他信息: 已有打开的与此 Comman ...
- Android_life,Intent_note
生命周期: 从出生到死亡 Activity生命周期的7个方法和3个循环 onCreate() 创建时调用onRestart() 不可见到可见时调用onStart() 用户可见时调用onResume() ...
- Java并发——线程池Executor框架
线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...
- BFM1
BFM应该描述的是具有某种具体功能的电路.比如说,你的待测电路是一个智能卡,那他的BFM就是读卡器:那你就要根据协议,在BFM中描述出读卡器的具体行为. 写BFM就类似于写testbench了.BFM ...
- day0
/* 考前最后一天了 由于下午赶路 就放到上午发了 早晨浏览博客 上午浏览博客 感谢学弟为我写的博客233 很开心认识你们这一群人 嗯 最后一天了 就要说再见了 大家加油吧 ^ ^ */
- day-5
/* 还有几半天了 上午考试暴力暴力暴力... 亏我还写了对拍 没有卵用 T2 差点事 T3不难却没咋么认真想 这tm就很尴尬了23333 下午整理题 一下午.... 晚上打月赛 + 单调队列 继续说 ...