mina框架源码阅读与分析

Mina框架与源码的简单理解

 

.Mina架构图:

其框架实现如下图所示:(图来自于网上:

mina框架源码阅读与分析_第1张图片

 

.Mina 一个请求的主要实现流程:

       服务器启动时,构造NioSocketAcceptor,服务器同时也会构造NioProcessor

    client请求->NioSocketAcceptor建立连接,在bind监听端口后,调用startupAcceptor()方法->接收线程Acceptor启动->processHandles()方法调用->初始化session,并把session加入到NioProcessor待处理session队列中。

       当始化session,NioProcessor已经在通道中注册可读事件,同时add(T session)方法调用后->启动startupProcessor()方法->处理线程Processor启动->然后读事件读取数据时会在通道中执行过滤器连。

    如果有相应的业务处理,则调用相应的IoHandler(),然后组织返回给client的数据,经过数据经过滤连,数据发出。

 

一般我们自己写nio服务器端时,只有一个selector,但mina框架使用了两个选择器selector,其中一个用来建立连接,其核心为NioSocketAcceptor

另一个负责读写事件的,其核心为NioProcessor

 

.NioSocketAcceptor相关说明

1.NioSocketAcceptor的父类为AbstractPollingIoAcceptor,很多实现是在父类中实现的。在构造此类的时候,同时也构造了NioProcessor类,代码如下:

protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,

            Class<? extends IoProcessor<T>> processorClass) {

        this(sessionConfig, null, new SimpleIoProcessorPool<T>(processorClass),

                true);

    }

并且NioProcessor的个数为cpu+1

private static final int DEFAULT_SIZE = Runtime.getRuntime()

            .availableProcessors() + 1;

2.init方法,打开selector通道;aceeptor()方法处理接收连接,把SocektChannel绑定到NioSession;open()方法是打开serversocketchannel,然后配制socket的一些基本属性,并注册此事件是可连接的事件。

socket.bind(localAddress, getBacklog());

// Register the channel within the selector for ACCEPT event

channel.register(selector, SelectionKey.OP_ACCEPT);

 

3.父类中有内部线程类Acceptor,主要负责轮询处理注册过连接事件的请求建立起连接。此线程类是在startupAcceptor()方法中调用,代码如下:

private void startupAcceptor() {

        // If the acceptor is not ready, clear the queues

        // TODO : they should already be clean : do we have to do that ?

        if (!selectable) {

            registerQueue.clear();

            cancelQueue.clear();

        }

 

        // start the acceptor if not already started

        synchronized (lock) {

            if (acceptor == null) {

                acceptor = new Acceptor();

                executeWorker(acceptor);

            }

        }

}

 

.NioProcessor相关说明:

1.NioProcessor 在接收连接之后,另开了一个selector,用来处理读写事件。其大部分功能,在父类AbstractPollingIoProcessor中实现

 

2.Mina中用NioSession来封装了channel对应的读写操作等功能.

 

3.NioProcessor类中init方法为:

protected void init(NioSession session) throws Exception {

        SelectableChannel ch = (SelectableChannel) session.getChannel();

        ch.configureBlocking(false);

        session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));

}

很明显注册了读事件,并与相应的NioSession对应起来。

 

4.NioProcessor类中表面上看代码好像没有注册过写事件,而且实际应用中,读写事件是来回切换的。但是实际上NioProcessor用另外的方法实现了:

setInterestedInRead()

setInterestedInWrite()

这两个方法通过key.interestOps(newInterestOps)来实现事件切换,从而达到了注册读写事件的作用。

要明白读写注册事件,首先得明白SocketChannel注册事件的原理,一个通道每次注册时只对应一个事件,而每次注册不同事件时,只是对此通道的事件进行了切换而已。所以通过key.interestOps(ops)方法是实现了最原始的操作,即切换通道事件。

 

5NioSessionreadwrite方法同Buffer中一样。

 

6.IoSessionIterator<NioSession> an encapsulating iterator 。是NioProcess一个内部类

实现了iterator<NioSession> 接口的类,主要是重写了其方法public NioSession next(),目的是把迭代key时,把NioSession取出。

public NioSession next() {

        SelectionKey key = iterator.next();

        NioSession nioSession =  (NioSession) key.attachment();

        return nioSession;

}

.NioProcessor 父类AbstractPollingIoProcessor的相关实现:

1.Processor,为父类的内部线程类,在startProcessor()方法调用,通过executor启动此线程。一般请求在NioSocketAcceptor上建立连接后,然后启动NioProcessor中的工作线程Processor。一般也不是马上企动的,需要在调用addNew方法后,有新的请求后才会调用。

 

2.此类中有四个ConcurrentLinkedQueue分别用来存储创建,删除,操作中的session。其中值的说明的是flushingSessions是用来写session

 

3.executorNioProcessor工作线程,默认实现为:Executors.newCachedThreadPool()来定义。

 

4.startupProcessor()方法,开始工作线程,此处把processor内部线程类放入线程池中运行。如果select()出现阻塞,才马上唤醒,在processor线程每次select时间为一秒

private void startupProcessor() {

        synchronized (lock) {

            if (processor == null) {

                processor = new Processor();

                executor.execute(new NamePreservingRunnable(processor,

                        threadName));

            }

        }

 

        // Just stop the select() and start it again, so that the processor

        // can be activated immediately.

        wakeup();

  }

 

5.handNewSessions(T session) 从新session队列中取出所有待处理的session.然后通过addNow(T Session)session init(),buildfilterchain过滤这些等。最后返回处理了session的数量。另外也有对应的removeSession()方法

 

6.read(T session)是读取session里面的数据。如果读取数据的容易超过初始时设定的buffer大小时buffer会自动增加。写数据是通过writeBuffer()方法实现,往外写数据buffer大小也自动增加。

在此处要说明的,在此调用的readwritebuffer方法并不是最上层的方法,而是通过firechain连,调用fireMessageReceived(buf),以及fireMessageSent(session,buf)来读写。

请求到达时实例IoProcessor在会话通道中会执行过滤器链。

另外,如果此请求还有逻辑处理的话,接着也会执行相应的IoHandler

 

.MinaIoProcessor处理方式

       Mina 默认的线程工作方式为一个IoProcessor 负责执行一个会话上的所有过滤器、IoHandler,也就是对于IO 读写操作来说,是单线程工作方式(就是按照顺序逐个执行)。假如你想让某个事件方法(譬如:sessionIdle()sessionOpened()等)在单独的线程中运行(也就是非IoProcessor 所在的线程),那么这里就需要用到一个ExecutorFilter 的过滤器。

    增加一个ExecutorFilter代码如下:

       acceptor.getFilterChain().addLast("exceutor", new ExecutorFilter()); 对于ExecutorFilter默认线程实现方式也可以修改。

你可能感兴趣的:(框架,工作,session,服务器,buffer,Mina)