MINA源代码分析之启动与绑定

最近认真看了看MINA的源代码,阅读代码过程中学到了不少新东西,对于多线程和NIO有了更深的了解。鉴于在网上无法找到相关的源代码分析,
让我在刚开始看时走了不少弯路,因此在看代码时特意做笔记。
以下便是我的笔记,主要讲述了MINA的启动与绑定SocketAddress时其内部实际做的工作。
对于其中一些并不重要的部分在这边略去了,对于消息到达后最终如何流转到IoHandler部分在这次里面并没有涉及,这部分下次再谈。
在看源代码的过程中,有一个小小的心得,采用Debug的方式来看处理流程比直接看代码要有效的多!
当然Debug时,也得记下执行的路径。在Debug过程中,顺便复习了一下类的装载和初始化过程。
下面是笔记的具体内部:
MINA初始化调用过程  -- 对应于NioAcceptor acceptor = new NioAcceptor(); 语句。
1.AbstractIoService的<clinit>方法, (最先初始化继承树中最顶层super class,先调用<clinit>方法)
2.初始化DefaultSocketSessionConfig对象,先调<clinit>初始化所有类变量,再调用构造方法
3.执行AbstractPollingIoAcceptor初始化
    3.1初始化SimpleProcessorPool,生成一个若干的IoProcessor对象
        3.1.1 初始化SimpleProcessorPool中的实例变量,执行初始化方法<init>,生成Executor对象
        3.1.2 通过reflection 调用 newInstance方法初始化IoProcessor,具体过程如下:
            3.1.2.1 执行AbstractPollingIoProcessor的<clinit>方法初始化类变量
            3.1.2.2 执行<init>方法,初始化各实例变量,包括如下Queue:          
newSessions,removingSessions,flushingSessions,trafficControllingSessions,disposalFuture。
            3.1.2.3 执行构造方法AbstractPollingIoProcessor(Executor executor),初始化threadName,设置executor对象。
            3.1.2.4 执行NioProcessor构造方法  Selector.open();
    3.2 调用AbstractIoService的初始化方法,先初始化各实例对象,包括IoServiceListener(用于监听
future),IoFilterChainBuilder,IoSessionDataStructureFactory,IoServiceStatistics,IoServiceListenerSupport,
创建Executor对象。
    3.3 调用AbstractIoAcceptor的初始化方法<init>
        3.3.1 初始化LocalAddresses队列,boundAddresses Set(管理请求绑定的SocketAddress的容器),以及绑定的对象锁
    3.4 调用AbstractPollingIoAcceptor的<init>方法,执行初始化
        3.4.1 初始化registerQueue(注册请求队列),cancelQueue(取消请求队列),boundHandles(socketAddress,ServerSocketChannel的Map)。
        3.4.2 关联IoProcessor对象
        3.4.3 初始化Selector  Selector.open(),并将selectable设置为true
3.5 执行NioSocketAcceptor的构造方法中其它的操作,调用DefaultSocketSessionConfig的init方法。
绑定SocketAddress过程  -- 对应于代码中的  acceptor.bind(new SocketAddress(null,80));
1 调用AbstractIoAcceptor类中的bind方法,
    调用AbstractPollingIoAcceptor中的bind0方法,bind0过程如下:
    a.创建新的AcceptorOperationFuture对象的实例
    b.将这个实例放到registerQueue中,供后面的方法处理
    c.startupAcceptor 创建一个新的线程,具体的工作为inner class Acceptor, Acceptor处理过程下面讲述。
    d.selector.wakeup 继续select操作
    e.返回已经绑定的Set<SocketAddress>
2.绑定成功后触发fireServiceActivated事件。
AbstractPollingIoAcceptor.Acceptor类处理流程
    1 先select
    2 处理注册绑定请求 registerHandles(),该方法在AbstractPollingIoAcceptor中。
        a.从registerQueue中取出future
        b.通过Future中的取出的SocketAddress创建ServerSocketChannel,并绑定。
        c.以SocketAddress为key将绑定后的ServerSocketChannel放到Map中,供后面处理。
        d.该Future设置为done,并将Selector wakeup.
    3 判断是否有SelectionKey需要处理,如果需要,则进行处理,processHandles() 方法:
        a.通过NioSocketAcceptor.accept得到一个SocketChannel,生成一个NioSocketSession对象。
        b.finishSessionInitialization,设置该NioSocketSession的属性,
        c.包括AbstractIoSession中的WriteRequestQueue,
        d.调用AbstractPollingIoProcessor.add()方法,将该Session添加到newSessions容器中, 通过Executor对象创建一个新的线程处理,具体处理类
AbstractPollingIoProcessor.Process类。Process线程处理流程下面详细描述。
    4 处理取消请求,unregisterHandles()方法,从cancelQueue中取数据进行处理,关闭ServerSocketChannel,SelectionKey.cancel()。
    5 判断是否仍有在监听的请求,如是没有,释放相关资源,并退出。
AbstractPollingIoProcessor.Processor处理流程
    1、调用NioProcess中的selector进行select操作,
    2、处理newSessions中的IoSession对象 (AbstractPollingIoProcessor.add())
        a.从newSessions中得到session,为这些session注册READ事件
        b.为每个个session创建filter chain
        c.触发IoServiceListenerSupport的sessionCreate事件。
    3、为SocketChannel注册合适的事件  updateTrafficMask()方法
        a.根据SelectionKey的状态注册该Session感兴趣的事件
        b.read事件注册时,判断是否已经注册过,如果没有,则注册。
        c.调用setInterestedInWrite方法通过该session的writeQueue中的请求,注册WRITE事件。
    4、如果之前select有数据,则处理session,process()方法,具体处理如下:
        如果是读,用read()方法处理
            a.读取数据,并触发filterChain的messageReceived方法,将数据通过filterChain流转到最后的Handler去处理。
            b.如果没有可读数据,将session对象放入removeSessiong队列。
        如果是写出,用write()方法处理,直接放入flushingSessions队列,由后面步骤进行处理。
    5、处理flushingSessions队列中的请求,将数据写到SocketChannel中,并触发FilterChain中的fireMessageSent事件。
    6、处理removeSessiong队列中的请求,将不需要的session Close掉,如果session在还有数据,则触发FilterChain的fireMessageSent方法。
关闭SocketChannel连接,distory掉IoSession,并触发fireSessionDestroyed事件。
    7、notifyIdleSessions方法,最终调用filterChain的fireSessionIdle方法。
    8、判断是否仍然存在打开的session,如果没有则做退出操作。
通过MINA的启动和流程可以看到,在多线程环境中应用了大量的Queue,Set,Map的对象来存储需要接下来进行的操作,这样做的原因应
该是出于性能考虑。也有利于子线程与父线程之间的通信,有利于减少代码之间的依赖。其中还存在大量的子线程回调父线程的方法来完成一些操作,和平时用到的
直接生成一个新的工作线程去处理,之后便不管有非常大的区别。这种模式下,死锁的问题的判断就显得很重要。
由于代码量比较大,超过了我的理解范围,在很多时候仍然没有把这个框架完全吃透。

你可能感兴趣的:(Mina)