zoukankan      html  css  js  c++  java
  • 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的编码器规则是一样的,以保证服务器解码成功;

     

     

     

     

     

  • 相关阅读:
    HDU-2502-月之数
    C语言的位运算的优势
    HDU-1026-Ignatius and the Princess I
    HDU-1015-Safecracker
    HDU-1398-Square Coins
    HDU-1028-Ignatius and the Princess III
    背包的硬币问题
    HDU-1527-取石子游戏
    HDU-1996-汉诺塔VI
    css中的选择器
  • 原文地址:https://www.cnblogs.com/xiashiwendao/p/4510262.html
Copyright © 2011-2022 走看看