MINA框架源码分析(三)

我们接着上一篇继续分析;

        在addNow方法执行结束之后,我们已经为当前NioProcessor里面所有的NioSocketSession对应的SocketChannel注册了OP_READ事件,接下来继续查看Processor的run方法,源码在上一篇中有,执行到第49行,判断如果selected大于0执行第52行的process方法,selected的值其实就是Selector的select方法返回值,表示客户端存在和服务端交互的请求,那么我们看看process做了些什么事:

        AbstractPollingIoProcessor$process()

[java]  view plain  copy
  1. private void process() throws Exception {  
  2.        for (Iterator<S> i = selectedSessions(); i.hasNext();) {  
  3.            S session = i.next();  
  4.            process(session);  
  5.            i.remove();  
  6.        }  
  7.    }  
        可以发现他就是遍历那些已经发生注册事件的NioSocketSession集合,并且调用process(S session)方法:

        AbstractPollingIoProcessor$process()

[java]  view plain  copy
  1. private void process(S session) {  
  2.         // Process Reads  
  3.         if (isReadable(session) && !session.isReadSuspended()) {  
  4.             read(session);  
  5.         }  
  6.   
  7.         // Process writes  
  8.         if (isWritable(session) && !session.isWriteSuspended()) {  
  9.             // add the session to the queue, if it's not already there  
  10.             if (session.setScheduledForFlush(true)) {  
  11.                 flushingSessions.add(session);  
  12.             }  
  13.         }  
  14.     }  
        首先通过isReadable方法判断当前NioSocketSession对应的SocketChannel中是否注册过OP_READ事件,如果注册过的话,执行read(session)方法;

        AbstractPollingIoProcessor$read()

[java]  view plain  copy
  1. private void read(S session) {  
  2.         IoSessionConfig config = session.getConfig();  
  3.         int bufferSize = config.getReadBufferSize();  
  4.         IoBuffer buf = IoBuffer.allocate(bufferSize);  
  5.   
  6.         final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();  
  7.   
  8.         try {  
  9.             int readBytes = 0;  
  10.             int ret;  
  11.   
  12.             try {  
  13.                 if (hasFragmentation) {  
  14.   
  15.                     while ((ret = read(session, buf)) > 0) {  
  16.                         readBytes += ret;  
  17.   
  18.                         if (!buf.hasRemaining()) {  
  19.                             break;  
  20.                         }  
  21.                     }  
  22.                 } else {  
  23.                     ret = read(session, buf);  
  24.   
  25.                     if (ret > 0) {  
  26.                         readBytes = ret;  
  27.                     }  
  28.                 }  
  29.             } finally {  
  30.                 buf.flip();  
  31.             }  
  32.   
  33.             if (readBytes > 0) {  
  34.                 IoFilterChain filterChain = session.getFilterChain();  
  35.                 filterChain.fireMessageReceived(buf);  
  36.                 buf = null;  
  37.   
  38.                 if (hasFragmentation) {  
  39.                     if (readBytes << 1 < config.getReadBufferSize()) {  
  40.                         session.decreaseReadBufferSize();  
  41.                     } else if (readBytes == config.getReadBufferSize()) {  
  42.                         session.increaseReadBufferSize();  
  43.                     }  
  44.                 }  
  45.             }  
  46.   
  47.             if (ret < 0) {  
  48.                 // scheduleRemove(session);  
  49.                 IoFilterChain filterChain = session.getFilterChain();  
  50.                 filterChain.fireInputClosed();  
  51.             }  
  52.         } catch (Exception e) {  
  53.             if (e instanceof IOException) {  
  54.                 if (!(e instanceof PortUnreachableException)  
  55.                         || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())  
  56.                         || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {  
  57.                     scheduleRemove(session);  
  58.                 }  
  59.             }  
  60.   
  61.             IoFilterChain filterChain = session.getFilterChain();  
  62.             filterChain.fireExceptionCaught(e);  
  63.         }  
  64.     }  

        这部分代码比较长,我们了解主干就可以了;

        首先第4行创建了一个IoBuffer对象,其实这就是我们java NIO中的Buffer角色,接着看到调用了read(session, buf)方法,这个方法返回值大于0表示读取数据成功,具体这个方法里面执行了些什么我们可以到NioProcessor里面的read方法看看:

[java]  view plain  copy
  1. protected int read(NioSession session, IoBuffer buf) throws Exception {  
  2.       ByteChannel channel = session.getChannel();  
  3.   
  4.       return channel.read(buf.buf());  
  5.   }  
        其实很简单了,就是将通道中的数据写到我们的缓存中罢了,这就是NIO本身的用法;

        如果我们读取到了数据,就会执行第33行的if语句,在if语句块中会执行IoFilterChain的fireMessageReceived方法,其实呢,IoFilterChain就是我们的责任链,前面分析源码的过程中我们知道在创建NioSocketSession的时候会创建一个DefaultIoFilterChain出来,并且会在它里面创建一个EntryImpl链,默认情况下会创建一个HeadFilter链头和TailFilter链尾,那么这里的IoFilterChain其实就是对DefaultIoFilterChain进行转换过来的,默认情况下也就值存在链头和链尾了,我们在使用MINA的时候可以通过NioSocketAcceptor的getFilterChain获得其对应的IoFilterChain,其实getFilterChain的真正实现是在AbstarctIoService里面的,有了这个IoFilterChain之后,我们可以调用他的addLast方法为其添加我们自定义或者MINA自带的Filter对象,addLast的真正实现是在DefaultIoFilterChain里面的,我们可以看看:

[java]  view plain  copy
  1. public synchronized void addLast(String name, IoFilter filter) {  
  2.        checkAddable(name);  
  3.        register(tail.prevEntry, name, filter);  
  4.    }  
        间接调用了register方法,来看看register

[java]  view plain  copy
  1. private void register(EntryImpl prevEntry, String name, IoFilter filter) {  
  2.         EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);  
  3.   
  4.         try {  
  5.             filter.onPreAdd(this, name, newEntry.getNextFilter());  
  6.         } catch (Exception e) {  
  7.             throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);  
  8.         }  
  9.   
  10.         prevEntry.nextEntry.prevEntry = newEntry;  
  11.         prevEntry.nextEntry = newEntry;  
  12.         name2entry.put(name, newEntry);  
  13.   
  14.         try {  
  15.             filter.onPostAdd(this, name, newEntry.getNextFilter());  
  16.         } catch (Exception e) {  
  17.             deregister0(newEntry);  
  18.             throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);  
  19.         }  
  20.     }  
        如果你链表操作很熟的话,会发现其实这里进行的就是链表插入操作了,在第10行和11行可以体现出来,那么我们这里有个疑问了,链表操作的时候,我们只需要一个链头就可以了,没必要给链尾啊,这里的链尾是干嘛的呀,我来告诉你答案吧,链尾其实就是用来链接我们的IoHandler对象的,IoHandler是我们整个责任链的结束部分,我们真正的业务逻辑的处理都是在它里面完成的,所以你会发现在你使用MINA框架的时候,如果不给NioSocketAcceptor设置IoHandler的话是会报异常的,因为他是要进行业务逻辑处理的,没有他你整个程序是没法处理的,既然他是链接在链尾后面的,那么我们就该看看TailFilter的实现了:

        他是DefaultIoFilterChain的静态内部类,代码比较长,我就截取两个方法,其他的方法类似啦:

[java]  view plain  copy
  1. private static class TailFilter extends IoFilterAdapter {  
  2.        @Override  
  3.        public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {  
  4.            try {  
  5.                session.getHandler().sessionCreated(session);  
  6.            } finally {  
  7.                // Notify the related future.  
  8.                ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);  
  9.   
  10.                if (future != null) {  
  11.                    future.setSession(session);  
  12.                }  
  13.            }  
  14.        }  
  15.   
  16.        @Override  
  17.        public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {  
  18.            session.getHandler().sessionOpened(session);  
  19.        }  
        可以看到在TailFiler里面执行的方法实际上都是执行的IoHandler中对应的方法啦,也就是这样我们把Filter责任链和IoHandler联系到了一起;

        好了,扯得有点远了,继续回到我们的AbstractPollingIoProcessor里面的read方法,第33行在我们获取到数据之后首先会获得我们的DefaultIoFilterChain责任链,并且调用fireMessageReceived方法,我们来看看fireMessageReceived方法:

        这个方法位于DefaultIoFilterChain

[java]  view plain  copy
  1. public void fireMessageReceived(Object message) {  
  2.         if (message instanceof IoBuffer) {  
  3.             session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());  
  4.         }  
  5.   
  6.         callNextMessageReceived(head, session, message);  
  7.     }  
        可以看到他调用的是callNextMessageReceived方法
[java]  view plain  copy
  1. private void callNextMessageReceived(Entry entry, IoSession session, Object message) {  
  2.        try {  
  3.            IoFilter filter = entry.getFilter();  
  4.            NextFilter nextFilter = entry.getNextFilter();  
  5.            filter.messageReceived(nextFilter, session, message);  
  6.        } catch (Exception e) {  
  7.            fireExceptionCaught(e);  
  8.        } catch (Error e) {  
  9.            fireExceptionCaught(e);  
  10.            throw e;  
  11.        }  
  12.    }  
        在 callNextMessageReceived 方法中首先会获得当前Filter对象,接着获得当前Filter的nextFilter对象,接着调用filter的messageReceived方法,这个方法其实上执行的是DefaultIoFilterChain的 messageReceived方法:

[java]  view plain  copy
  1. public void messageReceived(IoSession session, Object message) {  
  2.                   Entry nextEntry = EntryImpl.this.nextEntry;  
  3.                   callNextMessageReceived(nextEntry, session, message);  
  4.               }  
        可以看到他还是执行的 callNextMessageReceived 方法,这样层层递归的执行,直到Filter的链尾,那么接下来就是执行IoHandler里面对应的 messageReceived 方法进行具体的业务逻辑操作喽!这样的话,整个read过程中涉及到的关键部分就结束啦!

        接下来分析下write过程,如果我们想要给服务端发送消息内容的话,首先我们需要获取到IoSession对象,这里我们以NioSocketSession为例,发送消息调用的将是他的write方法,查看NioSocketSession发现他里面没有write方法,到他的父类NioSession查看也不存在,最后在AbstractIoSession找到啦;

        AbstractIoSession$write()

[java]  view plain  copy
  1. public WriteFuture write(Object message) {  
  2.         return write(message, null);  
  3.     }  
        也就是说他执行的是两个参数的write方法,
[java]  view plain  copy
  1. public WriteFuture write(Object message, SocketAddress remoteAddress) {  
  2.         if (message == null) {  
  3.             throw new IllegalArgumentException("Trying to write a null message : not allowed");  
  4.         }  
  5.   
  6.         // We can't send a message to a connected session if we don't have  
  7.         // the remote address  
  8.         if (!getTransportMetadata().isConnectionless() && (remoteAddress != null)) {  
  9.             throw new UnsupportedOperationException();  
  10.         }  
  11.   
  12.         // If the session has been closed or is closing, we can't either  
  13.         // send a message to the remote side. We generate a future  
  14.         // containing an exception.  
  15.         if (isClosing() || !isConnected()) {  
  16.             WriteFuture future = new DefaultWriteFuture(this);  
  17.             WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);  
  18.             WriteException writeException = new WriteToClosedSessionException(request);  
  19.             future.setException(writeException);  
  20.             return future;  
  21.         }  
  22.   
  23.         FileChannel openedFileChannel = null;  
  24.   
  25.         // TODO: remove this code as soon as we use InputStream  
  26.         // instead of Object for the message.  
  27.         try {  
  28.             if ((message instanceof IoBuffer) && !((IoBuffer) message).hasRemaining()) {  
  29.                 // Nothing to write : probably an error in the user code  
  30.                 throw new IllegalArgumentException("message is empty. Forgot to call flip()?");  
  31.             } else if (message instanceof FileChannel) {  
  32.                 FileChannel fileChannel = (FileChannel) message;  
  33.                 message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());  
  34.             } else if (message instanceof File) {  
  35.                 File file = (File) message;  
  36.                 openedFileChannel = new FileInputStream(file).getChannel();  
  37.                 message = new FilenameFileRegion(file, openedFileChannel, 0, openedFileChannel.size());  
  38.             }  
  39.         } catch (IOException e) {  
  40.             ExceptionMonitor.getInstance().exceptionCaught(e);  
  41.             return DefaultWriteFuture.newNotWrittenFuture(this, e);  
  42.         }  
  43.   
  44.         // Now, we can write the message. First, create a future  
  45.         WriteFuture writeFuture = new DefaultWriteFuture(this);  
  46.         WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);  
  47.   
  48.         // Then, get the chain and inject the WriteRequest into it  
  49.         IoFilterChain filterChain = getFilterChain();  
  50.         filterChain.fireFilterWrite(writeRequest);  
  51.   
  52.         // TODO : This is not our business ! The caller has created a  
  53.         // FileChannel,  
  54.         // he has to close it !  
  55.         if (openedFileChannel != null) {  
  56.             // If we opened a FileChannel, it needs to be closed when the write  
  57.             // has completed  
  58.             final FileChannel finalChannel = openedFileChannel;  
  59.             writeFuture.addListener(new IoFutureListener<WriteFuture>() {  
  60.                 public void operationComplete(WriteFuture future) {  
  61.                     try {  
  62.                         finalChannel.close();  
  63.                     } catch (IOException e) {  
  64.                         ExceptionMonitor.getInstance().exceptionCaught(e);  
  65.                     }  
  66.                 }  
  67.             });  
  68.         }  
  69.   
  70.         // Return the WriteFuture.  
  71.         return writeFuture;  
  72.     }  
        这部分源码比较长,我们挑重点看,在第45行创建了一个 WriteFuture对象,接着把write的消息内容以及WriteFuture对象对象作为参数封装出来一个WriteRequest对象,第49行获得了我们的责任链,和read过程一样,我们也可以通过DefaultIoFilterChain的addLast方法添加自己创建的Filter对象,接着第50行调用DefaultIoFilterChain的fireFilterWrite方法

[java]  view plain  copy
  1. public void fireFilterWrite(WriteRequest writeRequest) {  
  2.       callPreviousFilterWrite(tail, session, writeRequest);  
  3.   }  
        可以看到这个方法执行的是callPreviousFilterWrite方法

[java]  view plain  copy
  1. private void callPreviousFilterWrite(Entry entry, IoSession session, WriteRequest writeRequest) {  
  2.     try {  
  3.         IoFilter filter = entry.getFilter();  
  4.         NextFilter nextFilter = entry.getNextFilter();  
  5.         filter.filterWrite(nextFilter, session, writeRequest);  
  6.     } catch (Exception e) {  
  7.         writeRequest.getFuture().setException(e);  
  8.         fireExceptionCaught(e);  
  9.     } catch (Error e) {  
  10.         writeRequest.getFuture().setException(e);  
  11.         fireExceptionCaught(e);  
  12.         throw e;  
  13.     }  
  14. }  
        和之前的read方法中责任链的执行过程一样,也是首先获取filter对象,同时获取该filter对象的下一个nextFilter对象,调用他的filterWrite方法

[java]  view plain  copy
  1. @Override  
  2.        public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {  
  3.            nextFilter.filterWrite(session, writeRequest);  
  4.        }  
        它里面调用的是filterWrite方法,这个方法里面会继续调用filterWrite方法,这样层层递归,直到到达责任链的链头,也就是HeadFilter为止,调用HeadFilter的filterWrite方法,HeadFilter是DefaultIoFilterChain的静态内部类:

[java]  view plain  copy
  1. public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {  
  2.   
  3.            AbstractIoSession s = (AbstractIoSession) session;  
  4.   
  5.            // Maintain counters.  
  6.            if (writeRequest.getMessage() instanceof IoBuffer) {  
  7.                IoBuffer buffer = (IoBuffer) writeRequest.getMessage();  
  8.                // I/O processor implementation will call buffer.reset()  
  9.                // it after the write operation is finished, because  
  10.                // the buffer will be specified with messageSent event.  
  11.                buffer.mark();  
  12.                int remaining = buffer.remaining();  
  13.   
  14.                if (remaining > 0) {  
  15.                    s.increaseScheduledWriteBytes(remaining);  
  16.                }  
  17.            } else {  
  18.                s.increaseScheduledWriteMessages();  
  19.            }  
  20.   
  21.            WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue();  
  22.   
  23.            if (!s.isWriteSuspended()) {  
  24.                if (writeRequestQueue.isEmpty(session)) {  
  25.                    // We can write directly the message  
  26.                    s.getProcessor().write(s, writeRequest);  
  27.                } else {  
  28.                    s.getWriteRequestQueue().offer(s, writeRequest);  
  29.                    s.getProcessor().flush(s);  
  30.                }  
  31.            } else {  
  32.                s.getWriteRequestQueue().offer(s, writeRequest);  
  33.            }  
  34.        }  
        在 HeadFilter的filterWrite方法里面,你会看到有这么一句代码s.getProcessor(),他其实上就是获得处理我们当前NioSocketSession的NioProcessor对象而已,那么接下来的write操作是包含两个参数的,我们的NioProcessor里面并没有实现这个方法,需要到他的父类AbstractPollingIoProcessor查看,代码如下:

[java]  view plain  copy
  1. public void write(S session, WriteRequest writeRequest) {  
  2.       WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();  
  3.   
  4.       writeRequestQueue.offer(session, writeRequest);  
  5.   
  6.       if (!session.isWriteSuspended()) {  
  7.           this.flush(session);  
  8.       }  
  9.   }  
        做的事还是比较少的,就是将当前的写请求加入到我们当前NioSocketSession的写请求队列中,同时通过AbstractPollingIoProcessor的flush方法将NioSocketSession放入到flushingSessions队列中,这个队列主要存储的是那些将要被flush的IoSession集合;我们来看看flush方法

        AbstractPollingIoProcessor$flush

[java]  view plain  copy
  1. public final void flush(S session) {  
  2.         // add the session to the queue if it's not already  
  3.         // in the queue, then wake up the select()  
  4.         if (session.setScheduledForFlush(true)) {  
  5.             flushingSessions.add(session);  
  6.             wakeup();  
  7.         }  
  8.     }  
        第5行执行了将当前NioSocketSession加入到flushingSession的操作,随后调用了wakeup方法,wakeup方法会唤醒我们阻塞的select方法,这样的话,我们的服务端就可以收到客户端发送的消息了,接着读取过程就和上面的源码讲解一样了;

        至此,MINA中主要的服务端源码分析结束了,注意我们只分析了NioSocketAcceptor部分的源码,没有涉及NioSocketConnector部分,其实NioSocketConnector部分的源码和NioSocketAcceptor部分基本上是类似的分析过程,在这里我就不细细分析了,下一篇我会对MINA框架做一个小结,包括它里面涉及到的一些线程模型结构;

猜你喜欢

转载自blog.csdn.net/gavin5033/article/details/80434163
今日推荐