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. [AngularJS] angular-formly: expressionProperties

    angular-formly provides a very simple API to dynamically change properties of your field (like disab ...

  2. 读完了csapp(中文名:深入理解计算机系统)

    上个星期最终把csapp看完了. 我买的是中文版的,由于除了貌似评价不错以外,由于涉及到些自己不了解的底层东西,怕是看英文会云里雾里.如今看来,大概不能算是个长处,可是的确可以加快我的看书速度,否则一 ...

  3. Enable SPI 1.0 and 1.1 with device tre overlays on BeagleBone

    For most people the above image means absolutely nothing, but for that one guy that has been searchi ...

  4. 分享asp.net学习交流社区

    亲们 最近发现一个很好的asp.net学习交流的QQ群——237221223.爱好asp.net的亲们可以加入到大家庭中去哈.大家在一起交流学习

  5. DHCPv6 server port and DHCPv6 client port

    The DHCPv6 draft says that, the port numbers for client and agents are given as 546 & 547 在wires ...

  6. 对于top.ascx里面可以不可以放置css的文件进行一个讲解

    今天遇到一个这样的问题就是把网站上面的flash做的导航栏和图片动画替换成html+css的代码,然而asp.net里面的页面又是xx.ascx的文件夹,当时我就晕了不知道改如何去下手,我就把里面的c ...

  7. Java实战之01Struts2-03属性封装、类型转换、数据验证

    九.封装请求正文到对象中 1.静态参数封装 在struts.xml配置文件中,给动作类注入值.调用的是setter方法. 原因:是由一个staticParams的拦截器完成注入的. 2.动态参数封装: ...

  8. UVA 11078 Open Credit System(扫描 维护最大值)

    Open Credit System In an open credit system, the students can choose any course they like, but there ...

  9. 导入外部jar包的方法

    注:使用的编译平台为eclipse <算法>一书中需要引入外部jar包(algs4.jar),因此特地去学了下导入外部jar包的方法.步骤如下: 1.先将algs4.jar拷到j如下路径: ...

  10. leetcode344——Reverse String(C++)

    Write a function that takes a string as input and returns the string reversed. Example:Given s = &qu ...