mina框架源代码研究

转自:http://blog.csdn.net/gaolingep/archive/2009/05/04/4147697.aspx

第一部分:mina各层的关系

图1.1

说明

  1. IOService:
    1. 这个接口抽象了一切I/O操作,包括建立端口监听、I/O读写,
  2. IOProcessor:
    1. 为IOService处理正真的I/O读写操作。 IOService在某端口监听,当发生int selected = select();时,说明有建立连接的客户端请求,IOService会调用IOProcessor,将session和交给processor处理。
    2. IOProcessor也会有一个int selected = select(1000);的阻塞,等待IO事件。
    3. 当I/O事件到达后,会把输入读入到一个BUF中session.getChannel().read(buf.buf())(Java NIO)
  3. IOFilter:
    1. 上面IOProcessor得到buf后,会交给 IOFilter处理,如果是读取IO则触发messageReceived 方法。
    2. IOFilter一般被包含在一个IoFilterChain中,顾名思义,当然是实现了责任链模式的一根链条咯。
  4. IoHandler
    1. 是拿到 buf 做处理的一个接口,是用户最终会面对的一个接口。
    2. 上面的 IOFilter得到buf(以接收数据为例),IOFilter调用了IoHandler messageReceived(s, message); 方法。

最后还要提一个接口:

IoSession

A handle which represents connection between two end - points regardless of

transport types.

实际上这个接口是一个会话服务,或者它更像是一个大容器。后面我们还会讲到它。

 

第二部分:类图

2.1 IOService

  1. IoAcceptor 接口:

服务器端接口,接受客户端访问的请求

  1. AbstractIoService

    设定处理函数、Filter、IoServiceListener

    1. 处理函数是一个Executor 或者是 Executor 的包装。
    2. IoServiceListener 可以用于打印日志,主要有 Service 启动、停止、空闲等监听方法
  2. AbstractIoAcceptor完成绑定监听端口
  3. AbstractPollingIoAcceptor执行具体的监听连接以及监听I/O事件
  4. NioSocketAcceptor用JAVA NIO的方式实现了具体的连接方法ServerSocketChannel ,例如 open accept

 

2.2IoProcessor

显然,这个结构实现了组成模式

SimpleIoProcessorPool内有一个数组,包装了IoProcessor 。这个 SimpleIoProcessorPool的DEFAULT_SIZE 属性, 定义了开多少个IoProcessor

前面讲过 IoProcessor 为IOService处理正真的I/O读写操作。(在nio下,一个IoProcessor 可以在单线程中处理多个连接请求和 io 事件)除此之外,再开多个 IoProcessor ,一个 IoProcessor 启动一个线程。

 

2.3 IoSession

第三部分 源码解读

3.1初始化

SocketAcceptor acceptor = new NioSocketAcceptor();

图1.1中,我们看到, mina 会首先把请求交给 IOService。实际上,这个接口也是用户首先面对的接口。

  1. 用户在这个端口上执行setHandler (IoHandler handler) 方法。
  2. 并执行 IoAcceptor 接口的 bind (SocketAddress localAddress) 方法。
  3. 实例化SocketAcceptor ,会 super() 其父类的构造函数。

我们依次看看三个父类的构造函数

  1. AbstractPollingIoAcceptor

protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,

Classextends IoProcessor> processorClass) {

this (sessionConfig, null , new SimpleIoProcessorPool(processorClass),

true );

}

  • 构造函数AbstractPollingIoAcceptor(new DefaultSocketSessionConfig(), NioProcessor.class); 定义了默认的 SessionConfig NioProcessor
  • new SimpleIoProcessorPool(processorClass) 是把 NioProcessor 包装成了 pool. 看类图 IoProcessor 就很好理解了,这是一个组成模式。

 

  1. AbstractIoAcceptor

protected AbstractIoAcceptor(IoSessionConfig sessionConfig, Executor executor) {

super (sessionConfig, executor);

defaultLocalAddresses .add( null );

}

AbstractIoAcceptor主要用来绑定监听端口。这个构造函数没有干其他的事情。

 

  1. AbstractIoService

protected AbstractIoService(IoSessionConfig sessionConfig, Executor executor)

  • 这个构造函数初始化 sessionConfig ,和当 executor 为空时,

if (executor == null ) {

System. out .println( "[GL:executor:]" +executor);

this . executor = Executors.newCachedThreadPool ();

createdExecutor = true ;

} else {

this . executor = executor;

createdExecutor = false ;

}

  • 这个构造函数还有一个监听器,或者叫监听池(可以包含多个监听器)。用来监听 service 创建、连接、断开等动作,当上述动作发生地时候,会调用 listener 。里面可以写自己的一些方法。

 

 

3.2 初始化2

acceptor.setHandler( new EchoProtocolHandler());

设定处理函数, EchoProtocolHandler() 是用户自己编写的一个 handle ,看图 1.1 可以知道,这是 mina 平台处理的最后一步。 Mina 把请求经过 ioprocessor 处理器、多个 iofilter 过滤器 处理后,才会交给 EchoProtocolHandler

我们看看从 IOService到IoHandler 之间发生了什么

 

3.3运行

在main()函数中,我们看到一个方法

acceptor.bind( new InetSocketAddress( PORT ));

这一个 bind 方法,表面看只是一个端口绑定,实际上发生了很多有趣的事情。

IOService 类图告诉我们, bind 端口应该是 AbstractIoAcceptor 干的事情,去这个类中找。

 

  1. AbstractIoAcceptor bind 方法

// 端口打包成一个 list, 以实现多端口监听

List localAddresses = new ArrayList(1);

localAddresses.add(localAddress);

 

然后调用了子类 AbstractPollingIoAcceptor bind0 方法

bind0(localAddressesCopy);

 

  1. AbstractPollingIoAcceptor. bind0 方法,把代码贴出来

protected final Set bind0(

Listextends SocketAddress> localAddresses) throws Exception {

 

     // 这个 request 包装了 localAddresses ,间接包装了 localAddress

AcceptorOperationFuture request = new AcceptorOperationFuture(

localAddresses);

 

// adds the Registration request to the queue for the Workers

// to handle

registerQueue .add(request);

 

// creates the Acceptor instance and has the local

// executor kick it off.

/*

         这个方法很重要,我们去看看发生了什么

*/

startupAcceptor();

 

// wakeup() selector.wakeup();

wakeup();

//bind0 结束

 

  1. startupAcceptor(); 方法内部代码。需要注意的是 Acceptor 不是 IOACCEPTOR ,这个 Acceptor 是一个线程,用于处理 IO 事件。

if ( acceptor == null ) {

     /*

                Acceptor 完成 监听连接事件

                 如果有感兴趣的连接发生,即调用 processHandles(selectedHandles());

     */

acceptor = new Acceptor();

// 调用爷爷类 AbstractIoService 的方法。

// acceptor 分配给线程池

executeWorker( acceptor );

}

 

  1. Acceptor ()代码

private class Acceptor implements Runnable {

public void run() {

int nHandles = 0;

 

while ( selectable ) { // 这个循环用来监听连接到达,以建立连接和 io 事件

try {

    System. out .println( "[GaoLing:] 连接建立 " );

int selected = select(); // 如果一直没有新连接,则一直会阻塞

 

/*

* 这个方法完成:打开 ServerSocketChannel 通道,注册感兴趣的监听

                     ServerSocketChannel 丢到 boundHandles 中去

                     就是在定义的若干个端口放置监听事件,接受 accept

                     注意:只是建立监听而已!还没有建立客户端连接!!

                     for (SocketAddress a : localAddresses) {

/*

* 这个 open 函数会调用子类 NioSocketAcceptor open 方法,

* 这个方法定义了一个通道,放置了一个感兴趣的 key:SelectionKey.OP_ACCEPT

* selector 去监听

* 返回一个 ServerSocketChannel

*/

H handle = open(a);

open(a); 内部实现

ServerSocketChannel channel = ServerSocketChannel.open ();

channel.configureBlocking( false );

ServerSocket socket = channel.socket();

socket.bind(localAddress, getBacklog());

channel.register( selector , SelectionKey. OP_ACCEPT );

*/

nHandles += registerHandles();

 

// 如果有感兴趣的事件到达

if (selected > 0) {

// We have some connection request, let's process

// them here.

                    // processHandles(selectedHandles()); 是很重要的方法,一会我们看看发生了什么

     // 开始调用 session

    // 一旦有 IO in out 事件进来,调用这个函数。

    // 这个函数有一个方法 session.getProcessor().add(session);

processHandles(selectedHandles());

}

 

。。。。。后面是回收处理,也很重要,但不在我们现在关注的范围内

} // while 循环

 

 

 

  1. processHandles 代码

private void processHandles(Iterator handles) throws Exception {

     // 注意这个 handles: ServerSocketChannelIterator, 不是我们的 IoHandler

while (handles.hasNext()) {

H handle = handles.next();

handles.remove();

 

/*

注意, session 出来了

* 参数 1 processor 就是 SimpleIoProcessorPool 的实例 , 第一部分讲了来历,这里再提一下

* AbstractPollingIoAcceptor 有构造函数

* protected AbstractPollingIoAcceptor(IoSessionConfig sessionConfig,

Class> processorClass) {

this(sessionConfig, null, new SimpleIoProcessorPool(processorClass) ,

true);

}

NioProcessor 进行了包装,成为 SimpleIoProcessorPool

 

* 参数 2 handle 包装了 selector.selectedKeys()

* 调用子类 NioSocketAcceptor accept 方法,

* 这个方法:

* SocketChannel client=server.accept();// 查找客户端套接字通道

* 初始化并返回 NioSocketSession 对象 return new NioSocketSession(this, processor, ch);

*/

T session = accept( processor , handle);

if (session == null ) {

break ;

}

 

// 这个方法比较复杂,不是我们今天讲得重点,先跳过去

//setAttributeMap

//setWriteRequestQueue

finishSessionInitialization(session, null , null );

 

// add the session to the SocketIoProcessor

// 完成了 session process 的绑定,并开始处理 handle

//session.getProcessor() 返回 SimpleIoProcessorPool

// 这个方法开启了一个线程,调用了 AbstractPollingIoProcessor add 方法

// 实际上上面我们说了, session.getProcessor() 得到的是 包装了 NioProcessor 对象的 SimpleIoProcessorPool NioProcessor 对象间接继承了 add 方法

// 看看这个 add 方法,调用了 startupWorker(); ,开启了一个线程

session.getProcessor().add(session);

}

}

}

 

  1. session.getProcessor().add(session); 方法

    这个方法调用了 SimpleIoProcessorPool.add 。即引出了自定义线程池。参看类图 Processor。具体就跳过去了。

public final void add(T session) {

if (isDisposing()) {

throw new IllegalStateException( "Already disposed." );

}

 

// Adds the session to the newSession queue and starts the worker

newSessions .add(session);

startupWorker();

}

 

  1. startupWorker() 方法

private void startupWorker() {

synchronized ( lock ) {

     // 这个 processor 不是 IOProcessor, 它只是一个线程,每隔 1s 种逐一通知 session

     // 这个线程会一直轮询下去, for(;;)

if ( processor == null ) {

processor = new Processor();

// 注: session 已被加载到 newSessions.add(session);

executor .execute( new NamePreservingRunnable( processor , threadName ));

}

}

wakeup();

}

 

  1. Processor 方法

private class Processor implements Runnable {

 

public void run() {

。。。。。。。。

for (;;) {

try {

// 调用子类 NioProcessor return selector.select(timeout);

     int selected = select(1000);

if (selected > 0) { // 如果有连接过来,就调用 process 方法

         process();

         }

// 否则执行 "idle"

。。。。。。。。。。。。。。

 

 

  1. process(); 方法

private void process() throws Exception {

for (Iterator i = selectedSessions(); i.hasNext();) {

    T session = i.next();

process(session);

i.remove();

}

}

  1. process(); 方法

private void process(T session) {

if (isReadable(session) && !session.isReadSuspended()) {

read(session);

}

 

if (isWritable(session) && !session.isWriteSuspended()) {

scheduleFlush(session);

}

}

 

快结束了

  1. read 方法

private void read(T session) {

IoSessionConfig config = session.getConfig();

//buf 存放了 channel.read 的结果

IoBuffer buf = IoBuffer.allocate (config.getReadBufferSize());

 

final boolean hasFragmentation =

session.getTransportMetadata().hasFragmentation();

 

try {

int readBytes = 0;

int ret;

 

// 初始化 buffer

             。。。。。。

 

if (readBytes > 0) {

            / / session.getFilterChain(), 以前没有讲过 filterChain 是从哪里来的 ,但是提到过 session NioSocketSession 的实例,这个类中定义了

//private final IoFilterChain filterChain = new DefaultIoFilterChain(this);

IoFilterChain filterChain = session.getFilterChain();

 

// 这句话包含了调用 handle ,把 buf 内容推送给它

//filterChain DefaultIoFilterChain 的实例

// 在这个方法里面,会调用用户 handle 的方法!

filterChain.fireMessageReceived(buf);

buf = null ;

 

。。。。

}

 

  1. filetr 内的方法摘要

IoFilter filter = entry.getFilter();

//nextFilter 实例化了本类的 EntryImpl 内部类

NextFilter nextFilter = entry.getNextFilter();

 

// 这个 filter 会调用 IoFilterAdapter messageReceived

filter.messageReceived(nextFilter, session,

message);

             。。。

  1. 调用 handle 修成正果

session.getHandler().messageReceived(s, message);

 

3.4总结一下流程

  1. 3.4.1 初始化

实例化 SocketAcceptor main ->

完成 sessionConfig IoProcessor 的初始化【 SocketAcceptor 父类】 ->

acceptor.setHandler main

 

  1. 3.4.2 运行(对照类图看)

acceptor.bind( new InetSocketAddress( PORT )); main ->

AbstractIoAcceptor.bind AbstractIoAcceptor ->

AbstractPollingIoAcceptor. bind0 AbstractPollingIoAcceptor ->

startupAcceptor() 【开线程,监听连接事件, AbstractPollingIoAcceptor ->

class Acceptor AbstractPollingIoAcceptor ->

processHandles(Iterator handles) AbstractPollingIoAcceptor ->

T session = accept( processor , handle); 【初始化 session, AbstractPollingIoAcceptor ->

session.getProcessor().add(session); 【处理 io 事件 ,AbstractPollingIoAcceptor ->

SimpleIoProcessorPool.add 【这里用到了自定义线程池(数组), SimpleIoProcessorPool ->

AbstractPollingIoProcessor.add 【调用 startupWorker() AbstractPollingIoProcessor ->

startupWorker(); 【处理 io 事件。 AbstractPollingIoProcessor ->

processor = new Processor(); 【线程池,处理 IO 输入输出数据, AbstractPollingIoProcessor ->

process() AbstractPollingIoProcessor ->

read(T session) AbstractPollingIoProcessor ->

filterChain->

handle

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章