Mina源码总结(一)

从Server和Client2个方向总结一下MINA的类设计,主要是基于NIO的。

一、公共类设计。

       Server和Client端都会继承或使用的类。

1、IoService:采用观察者模式的基础接口,Server和Client都会继承这个类的抽象实现类,将自己定义为被观察者。同时可以获取Session和FIlterChain。这种观察者的设计模式同Tomcat的LifeCycle设计。

2、AbstractIoService:IoService的抽象实现类,主要的属性是线程池executor,用于处理IO事件的IoHandler。

  采用匿名内部类的方式构造了一个观察者,用于监听该服务的启动。

  线程池的作用的对于每一个绑定的端口,采用单独的一个线程来执行通信。

3、IoServiceListenerSupport:用于保存所有观察者的辅助类。观察者的操作,和事件的触发都在这个类里。

二、Server

1、IoAcceptor:Server端的最底层接口。主要的方法为LoacaAddress的get和set,bind和unbind方法。当我们进行NIO的通信时,绑定监听的端口是必须的,这就是这个接口的作用。

2、AbstractIoAcceptor:实现IoAccpetor,继承AbstractIoService

     bind方法,绑定设置的端口,成功后触发观察者的服务启动事件。
public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {
        ...
        boolean activate = false;
        synchronized (bindLock) {
            synchronized (boundAddresses) {
                if (boundAddresses.isEmpty()) {
                    activate = true;
                }
            }

            if (getHandler() == null) {
                throw new IllegalStateException("handler is not set.");
            }

            try {
                //调用子类的方法实现绑定。
                Set<socketaddress> addresses = bindInternal(localAddressesCopy);

                synchronized (boundAddresses) {
                    boundAddresses.addAll(addresses);
                }
            } catch (IOException e) {
                throw e;
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new RuntimeIoException("Failed to bind to: " + getLocalAddresses(), e);
            }
        }

        if (activate) {
            //触发服务启动事件
            getListeners().fireServiceActivated();
        }
    }
</socketaddress>
线程池执行线程,子类会调用。
    protected final void executeWorker(Runnable worker) {
        executeWorker(worker, null);
    }

    protected final void executeWorker(Runnable worker, String suffix) {
        String actualThreadName = threadName;
        if (suffix != null) {
            actualThreadName = actualThreadName + '-' + suffix;
        }
        executor.execute(new NamePreservingRunnable(worker, actualThreadName));
    }

3、AbstractPollingIoAcceptor:继承AbstractIoAcceptor。

  定义了ServerSocketChannel的open,accept抽象方法以及Selector的open和select的抽象方法。

bind的最终实现方法。
protected final Set<socketaddress> bindInternal(List<? extends SocketAddress> localAddresses) throws Exception {
        ...
        //主要方法
        startupAcceptor();
        ...
    }
private void startupAcceptor() throws InterruptedException {  
        ...
        Acceptor acceptor = acceptorRef.get();
        //Acceptor为内部类,
        if (acceptor == null) {
            lock.acquire();
            acceptor = new Acceptor();
            //线程池执行该内部类
            if (acceptorRef.compareAndSet(null, acceptor)) {
                executeWorker(acceptor);
            } else {
                lock.release();
            }
        }
    }
private class Acceptor implements Runnable {
        public void run() {
            assert (acceptorRef.get() == this);

            int nHandles = 0;

            // Release the lock
            lock.release();

            while (selectable) {
                try {
                    //selector.select();
                    int selected = select();

                    //在管道上注册ACCPET事件,绑定端口
                    nHandles += registerHandles();

                    //没有成功绑定端口
                    if (nHandles == 0) {
                        acceptorRef.set(null);

                        if (registerQueue.isEmpty() && cancelQueue.isEmpty()) {
                            assert (acceptorRef.get() != this);
                            break;
                        }

                        if (!acceptorRef.compareAndSet(null, this)) {
                            assert (acceptorRef.get() != this);
                            break;
                        }

                        assert (acceptorRef.get() == this);
                    }
                    //成功绑定了端口,生成了SSc
                    if (selected > 0) {
                        //处理每个SSC,生成对应的Session
                        processHandles(selectedHandles());
                    }

                    // check to see if any cancellation request has been made.
                    nHandles -= unregisterHandles();
                } catch (ClosedSelectorException cse) {
                    // If the selector has been closed, we can exit the loop
                    ExceptionMonitor.getInstance().exceptionCaught(cse);
                    break;
                } catch (Exception e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        ExceptionMonitor.getInstance().exceptionCaught(e1);
                    }
                }
            }

            // Cleanup all the processors, and shutdown the acceptor.
            if (selectable && isDisposing()) {
                selectable = false;
                try {
                    if (createdProcessor) {
                        processor.dispose();
                    }
                } finally {
                    try {
                        synchronized (disposalLock) {
                            if (isDisposing()) {
                                destroy();
                            }
                        }
                    } catch (Exception e) {
                        ExceptionMonitor.getInstance().exceptionCaught(e);
                    } finally {
                        disposalFuture.setDone();
                    }
                }
            }
        }
private int registerHandles() {
        for (;;) {
            ...
            try {
                // Process all the addresses
                for (SocketAddress a : localAddresses) {
                    //调用父类方法,进行ServerSocketChannel生成等NIO初始化操作。循环遍历每个绑定的端口。
                    H handle = open(a);
                    //端口号的类为key,ServerSocketChannel为value存入map中。
                    newHandles.put(localAddress(handle), handle);
                }

                // Everything went ok, we can now update the map storing
                // all the bound sockets.
                boundHandles.putAll(newHandles);

                // and notify.
                future.setDone();
                return newHandles.size();
            } catch (Exception e) {
                // We store the exception in the future
                future.setException(e);
            } finally {
                // Roll back if failed to bind all addresses.
                if (future.getException() != null) {
                    for (H handle : newHandles.values()) {
                        try {
                            close(handle);
                        } catch (Exception e) {
                            ExceptionMonitor.getInstance().exceptionCaught(e);
                        }
                    }

                    // TODO : add some comment : what is the wakeup() waking up ?
                    wakeup();
                }
            }
        }
    }
protected ServerSocketChannel open(SocketAddress localAddress) throws Exception {
        //所有NIO的Server端初始化都在这里
        ServerSocketChannel channel = null;

        if (selectorProvider != null) {
            channel = selectorProvider.openServerSocketChannel();
        } else {
            channel = ServerSocketChannel.open();
        }

        boolean success = false;

        try {
            //非阻塞
            channel.configureBlocking(false);
            //获取socket
            ServerSocket socket = channel.socket();

            // Set the reuseAddress flag accordingly with the setting
            socket.setReuseAddress(isReuseAddress());

            try {
                //绑定
                socket.bind(localAddress, getBacklog());
            } catch (IOException ioe) {
                // Add some info regarding the address we try to bind to the
                // message
                String newMessage = "Error while binding on " + localAddress + "\n" + "original message : "
                        + ioe.getMessage();
                Exception e = new IOException(newMessage);
                e.initCause(ioe.getCause());

                // And close the channel
                channel.close();

                throw e;
            }

            //在SSC上注册ACCEPT事件
            channel.register(selector, SelectionKey.OP_ACCEPT);
            success = true;
        } finally {
            if (!success) {
                close(channel);
            }
        }
        return channel;
    }
private void processHandles(Iterator<h> handles) throws Exception {
            //循环处理每个SSC
            while (handles.hasNext()) {
                H handle = handles.next();
                handles.remove();
                //监听ACCEPT事件,有就新建Session
                S session = accept(processor, handle);

                if (session == null) {
                    continue;
                }
                //初始化
                initSession(session, null, null);

                //getProcessor()获取的是SimpleIoProcessorPool,add方法是拿到池子里的IOProcessor,然后添加session。
                session.getProcessor().add(session);
            }
        }
</h>
protected NioSession accept(IoProcessor<niosession> processor, ServerSocketChannel handle) throws Exception {

        SelectionKey key = null;

        if (handle != null) {
            //获取所有的事件
            key = handle.keyFor(selector);
        }
        //不是ACCEPT事件就返回
        if ((key == null) || (!key.isValid()) || (!key.isAcceptable())) {
            return null;
        }

        //接受客户端的SocketChannel,
        SocketChannel ch = handle.accept();

        if (ch == null) {
            return null;
        }
        //生成Session
        return new NioSocketSession(this, processor, ch);
    }
</niosession>
 public final void add(S session) {
        if (disposed || disposing) {
            throw new IllegalStateException("Already disposed.");
        }

        //往当前IOProcessor的队列里添加session
        newSessions.add(session);
        //和之前的startupAcceptor类似,通过IOProcessor的线程池执行processor。
        startupProcessor();
    }
private class Processor implements Runnable {
        public void run() {
            assert (processorRef.get() == this);

            int nSessions = 0;
            lastIdleCheckTime = System.currentTimeMillis();

            for (;;) {
                try {
                    ...                                      
                    //对Session处理,主要是在管道上注册READ事件,然后将Session附着(attach)在管道上。
                    nSessions += handleNewSessions();

                    updateTrafficMask();

                    // Now, if we have had some incoming or outgoing events,
                    // deal with them
                    if (selected > 0) {
                        //处理read和write事件
                        process();
                    }

                    // Write the pending requests
                    long currentTime = System.currentTimeMillis();
                    flush(currentTime);

                    // And manage removed sessions
                    nSessions -= removeSessions();

                    // Last, not least, send Idle events to the idle sessions
                    notifyIdleSessions(currentTime);

                    // Get a chance to exit the infinite loop if there are no
                    // more sessions on this Processor
                    if (nSessions == 0) {
                        processorRef.set(null);

                        if (newSessions.isEmpty() && isSelectorEmpty()) {
                            // newSessions.add() precedes startupProcessor
                            assert (processorRef.get() != this);
                            break;
                        }

                        assert (processorRef.get() != this);

                        if (!processorRef.compareAndSet(null, this)) {
                            // startupProcessor won race, so must exit processor
                            assert (processorRef.get() != this);
                            break;
                        }

                        assert (processorRef.get() == this);
                    }

                    // Disconnect all sessions immediately if disposal has been
                    // requested so that we exit this loop eventually.
                    if (isDisposing()) {
                        for (Iterator<> i = allSessions(); i.hasNext();) {
                            scheduleRemove(i.next());
                        }

                        wakeup();
                    }
                } catch (ClosedSelectorException cse) {
                    // If the selector has been closed, we can exit the loop
                    // But first, dump a stack trace
                    ExceptionMonitor.getInstance().exceptionCaught(cse);
                    break;
                } catch (Exception e) {
                    ExceptionMonitor.getInstance().exceptionCaught(e);

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        ExceptionMonitor.getInstance().exceptionCaught(e1);
                    }
                }
            }

            try {
                synchronized (disposalLock) {
                    if (disposing) {
                        doDispose();
                    }
                }
            } catch (Exception e) {
                ExceptionMonitor.getInstance().exceptionCaught(e);
            } finally {
                disposalFuture.setValue(true);
            }
        }
    }
private boolean addNow(S session) {
        boolean registered = false;

        try {
            //注册READ事件,管道附着Session
            init(session);
            registered = true;

            //建立Session中的FilterChain
            IoFilterChainBuilder chainBuilder = session.getService().getFilterChainBuilder();
            chainBuilder.buildFilterChain(session.getFilterChain());

            //观察者模式触发SessionCreated
            IoServiceListenerSupport listeners = ((AbstractIoService) session.getService()).getListeners();
            listeners.fireSessionCreated(session);
        } catch (Exception e) {
            ExceptionMonitor.getInstance().exceptionCaught(e);

            try {
                destroy(session);
            } catch (Exception e1) {
                ExceptionMonitor.getInstance().exceptionCaught(e1);
            } finally {
                registered = false;
            }
        }

        return registered;
    }
protected void init(NioSession session) throws Exception {
        SelectableChannel ch = (SelectableChannel) session.getChannel();
        ch.configureBlocking(false);
        //注册READ事件,管道附着Session
        session.setSelectionKey(ch.register(selector, SelectionKey.OP_READ, session));
    }
private void process(S session) {
        // 处理读取事件
        if (isReadable(session) && !session.isReadSuspended()) {
            read(session);
        }

        // 处理写事件
        if (isWritable(session) && !session.isWriteSuspended()) {
            // add the session to the queue, if it's not already there
            if (session.setScheduledForFlush(true)) {
                flushingSessions.add(session);
            }
        }
    }
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) {
                //有传输数据,这样通过责任链触发Server端的MessageReceived方法。
                //默认的责任链有TailFilter,其中的onMessageReceived会调用handler的onMessageReceived,
                //这样就会调用到我们初始化设置的handler了。
                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);
        }
    }
总结:1、服务端初始化时,会生成SimpleIoProcessorPool,用来处理Session。2、需要继承IoHandlerAdapter来实现自己的handler,用于接受消息。3、绑定端口的时候,会初始化NIO的ServerSocketChannel(SSC),注册ACCEPTOR事件。之后会通过IOService的线程池处理每一个端口的ACCEPTOR事件,成功后生成NioSocketSession,附着在SSC上。每个Session都会有IOProcessor,通过线程池,将SSC注册READ事件,同时监听是否有read事件,有read事件就触发责任链的onMessageReceived方法,最后会调用到自己实现的handler的onMessageReceived方法。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值