MINA框架源码分析(三)

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

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

        AbstractPollingIoProcessor$process()

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

        AbstractPollingIoProcessor$process()

private void process(S session) {
        // Process Reads
        if (isReadable(session) && !session.isReadSuspended()) {
            read(session);
        }

        // Process writes
        if (isWritable(session) && !session.isWriteSuspended()) {
            // add the session to the queue, if it's not already there
            if (session.setScheduledForFlush(true)) {
                flushingSessions.add(session);
            }
        }
    }
        首先通过isReadable方法判断当前NioSocketSession对应的SocketChannel中是否注册过OP_READ事件,如果注册过的话,执行read(session)方法;

        AbstractPollingIoProcessor$read()

private void read(S session) {
        IoSessionConfig config = session.getConfig();
        int bufferSize = config.getReadBufferSize();
        IoBuffer buf = IoBuffer.allocate(bufferSize);

        final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();

        try {
            int readBytes = 0;
            int ret;

            try {
                if (hasFragmentation) {

                    while ((ret = read(session, buf)) > 0) {
                        readBytes += ret;

                        if (!buf.hasRemaining()) {
                            break;
                        }
                    }
                } else {
                    ret = read(session, buf);

                    if (ret > 0) {
                        readBytes = ret;
                    }
                }
            } finally {
                buf.flip();
            }

            if (readBytes > 0) {
                IoFilterChain filterChain = session.getFilterChain();
                filterChain.fireMessageReceived(buf);
                buf = null;

                if (hasFragmentation) {
                    if (readBytes << 1 < config.getReadBufferSize()) {
                        session.decreaseReadBufferSize();
                    } else if (readBytes == config.getReadBufferSize()) {
                        session.increaseReadBufferSize();
                    }
                }
            }

            if (ret < 0) {
                // scheduleRemove(session);
                IoFilterChain filterChain = session.getFilterChain();
                filterChain.fireInputClosed();
            }
        } catch (Exception e) {
            if (e instanceof IOException) {
                if (!(e instanceof PortUnreachableException)
                        || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
                        || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {
                    scheduleRemove(session);
                }
            }

            IoFilterChain filterChain = session.getFilterChain();
            filterChain.fireExceptionCaught(e);
        }
    }

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

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

  protected int read(NioSession session, IoBuffer buf) throws Exception {
        ByteChannel channel = session.getChannel();

        return channel.read(buf.buf());
    }
        其实很简单了,就是将通道中的数据写到我们的缓存中罢了,这就是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里面的,我们可以看看:

 public synchronized void addLast(String name, IoFilter filter) {
        checkAddable(name);
        register(tail.prevEntry, name, filter);
    }
        间接调用了register方法,来看看register

private void register(EntryImpl prevEntry, String name, IoFilter filter) {
        EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);

        try {
            filter.onPreAdd(this, name, newEntry.getNextFilter());
        } catch (Exception e) {
            throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);
        }

        prevEntry.nextEntry.prevEntry = newEntry;
        prevEntry.nextEntry = newEntry;
        name2entry.put(name, newEntry);

        try {
            filter.onPostAdd(this, name, newEntry.getNextFilter());
        } catch (Exception e) {
            deregister0(newEntry);
            throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);
        }
    }
        如果你链表操作很熟的话,会发现其实这里进行的就是链表插入操作了,在第10行和11行可以体现出来,那么我们这里有个疑问了,链表操作的时候,我们只需要一个链头就可以了,没必要给链尾啊,这里的链尾是干嘛的呀,我来告诉你答案吧,链尾其实就是用来链接我们的IoHandler对象的,IoHandler是我们整个责任链的结束部分,我们真正的业务逻辑的处理都是在它里面完成的,所以你会发现在你使用MINA框架的时候,如果不给NioSocketAcceptor设置IoHandler的话是会报异常的,因为他是要进行业务逻辑处理的,没有他你整个程序是没法处理的,既然他是链接在链尾后面的,那么我们就该看看TailFilter的实现了:

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

 private static class TailFilter extends IoFilterAdapter {
        @Override
        public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
            try {
                session.getHandler().sessionCreated(session);
            } finally {
                // Notify the related future.
                ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);

                if (future != null) {
                    future.setSession(session);
                }
            }
        }

        @Override
        public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
            session.getHandler().sessionOpened(session);
        }
}
        可以看到在TailFiler里面执行的方法实际上都是执行的IoHandler中对应的方法啦,也就是这样我们把Filter责任链和IoHandler联系到了一起;

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

        这个方法位于DefaultIoFilterChain

public void fireMessageReceived(Object message) {
        if (message instanceof IoBuffer) {
            session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
        }

        callNextMessageReceived(head, session, message);
    }
        可以看到他调用的是callNextMessageReceived方法
 private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
        try {
            IoFilter filter = entry.getFilter();
            NextFilter nextFilter = entry.getNextFilter();
            filter.messageReceived(nextFilter, session, message);
        } catch (Exception e) {
            fireExceptionCaught(e);
        } catch (Error e) {
            fireExceptionCaught(e);
            throw e;
        }
    }
        在 callNextMessageReceived方法中首先会获得当前Filter对象,接着获得当前Filter的nextFilter对象,接着调用filter的messageReceived方法,这个方法其实上执行的是DefaultIoFilterChain的 messageReceived方法:

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

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

        AbstractIoSession$write()

public WriteFuture write(Object message) {
        return write(message, null);
    }
        也就是说他执行的是两个参数的write方法,
public WriteFuture write(Object message, SocketAddress remoteAddress) {
        if (message == null) {
            throw new IllegalArgumentException("Trying to write a null message : not allowed");
        }

        // We can't send a message to a connected session if we don't have
        // the remote address
        if (!getTransportMetadata().isConnectionless() && (remoteAddress != null)) {
            throw new UnsupportedOperationException();
        }

        // If the session has been closed or is closing, we can't either
        // send a message to the remote side. We generate a future
        // containing an exception.
        if (isClosing() || !isConnected()) {
            WriteFuture future = new DefaultWriteFuture(this);
            WriteRequest request = new DefaultWriteRequest(message, future, remoteAddress);
            WriteException writeException = new WriteToClosedSessionException(request);
            future.setException(writeException);
            return future;
        }

        FileChannel openedFileChannel = null;

        // TODO: remove this code as soon as we use InputStream
        // instead of Object for the message.
        try {
            if ((message instanceof IoBuffer) && !((IoBuffer) message).hasRemaining()) {
                // Nothing to write : probably an error in the user code
                throw new IllegalArgumentException("message is empty. Forgot to call flip()?");
            } else if (message instanceof FileChannel) {
                FileChannel fileChannel = (FileChannel) message;
                message = new DefaultFileRegion(fileChannel, 0, fileChannel.size());
            } else if (message instanceof File) {
                File file = (File) message;
                openedFileChannel = new FileInputStream(file).getChannel();
                message = new FilenameFileRegion(file, openedFileChannel, 0, openedFileChannel.size());
            }
        } catch (IOException e) {
            ExceptionMonitor.getInstance().exceptionCaught(e);
            return DefaultWriteFuture.newNotWrittenFuture(this, e);
        }

        // Now, we can write the message. First, create a future
        WriteFuture writeFuture = new DefaultWriteFuture(this);
        WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);

        // Then, get the chain and inject the WriteRequest into it
        IoFilterChain filterChain = getFilterChain();
        filterChain.fireFilterWrite(writeRequest);

        // TODO : This is not our business ! The caller has created a
        // FileChannel,
        // he has to close it !
        if (openedFileChannel != null) {
            // If we opened a FileChannel, it needs to be closed when the write
            // has completed
            final FileChannel finalChannel = openedFileChannel;
            writeFuture.addListener(new IoFutureListener<WriteFuture>() {
                public void operationComplete(WriteFuture future) {
                    try {
                        finalChannel.close();
                    } catch (IOException e) {
                        ExceptionMonitor.getInstance().exceptionCaught(e);
                    }
                }
            });
        }

        // Return the WriteFuture.
        return writeFuture;
    }
        这部分源码比较长,我们挑重点看,在第45行创建了一个 WriteFuture对象,接着把write的消息内容以及WriteFuture对象对象作为参数封装出来一个WriteRequest对象,第49行获得了我们的责任链,和read过程一样,我们也可以通过DefaultIoFilterChain的addLast方法添加自己创建的Filter对象,接着第50行调用DefaultIoFilterChain的fireFilterWrite方法

  public void fireFilterWrite(WriteRequest writeRequest) {
        callPreviousFilterWrite(tail, session, writeRequest);
    }
        可以看到这个方法执行的是callPreviousFilterWrite方法

    private void callPreviousFilterWrite(Entry entry, IoSession session, WriteRequest writeRequest) {
        try {
            IoFilter filter = entry.getFilter();
            NextFilter nextFilter = entry.getNextFilter();
            filter.filterWrite(nextFilter, session, writeRequest);
        } catch (Exception e) {
            writeRequest.getFuture().setException(e);
            fireExceptionCaught(e);
        } catch (Error e) {
            writeRequest.getFuture().setException(e);
            fireExceptionCaught(e);
            throw e;
        }
    }
        和之前的read方法中责任链的执行过程一样,也是首先获取filter对象,同时获取该filter对象的下一个nextFilter对象,调用他的filterWrite方法

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

 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {

            AbstractIoSession s = (AbstractIoSession) session;

            // Maintain counters.
            if (writeRequest.getMessage() instanceof IoBuffer) {
                IoBuffer buffer = (IoBuffer) writeRequest.getMessage();
                // I/O processor implementation will call buffer.reset()
                // it after the write operation is finished, because
                // the buffer will be specified with messageSent event.
                buffer.mark();
                int remaining = buffer.remaining();

                if (remaining > 0) {
                    s.increaseScheduledWriteBytes(remaining);
                }
            } else {
                s.increaseScheduledWriteMessages();
            }

            WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue();

            if (!s.isWriteSuspended()) {
                if (writeRequestQueue.isEmpty(session)) {
                    // We can write directly the message
                    s.getProcessor().write(s, writeRequest);
                } else {
                    s.getWriteRequestQueue().offer(s, writeRequest);
                    s.getProcessor().flush(s);
                }
            } else {
                s.getWriteRequestQueue().offer(s, writeRequest);
            }
        }
        在 HeadFilter的filterWrite方法里面,你会看到有这么一句代码s.getProcessor(),他其实上就是获得处理我们当前NioSocketSession的NioProcessor对象而已,那么接下来的write操作是包含两个参数的,我们的NioProcessor里面并没有实现这个方法,需要到他的父类AbstractPollingIoProcessor查看,代码如下:

  public void write(S session, WriteRequest writeRequest) {
        WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();

        writeRequestQueue.offer(session, writeRequest);

        if (!session.isWriteSuspended()) {
            this.flush(session);
        }
    }
        做的事还是比较少的,就是将当前的写请求加入到我们当前NioSocketSession的写请求队列中,同时通过AbstractPollingIoProcessor的flush方法将NioSocketSession放入到flushingSessions队列中,这个队列主要存储的是那些将要被flush的IoSession集合;我们来看看flush方法

        AbstractPollingIoProcessor$flush

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

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


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值