在分析代码之前不得不先了解下netty的线程模型,脑中有了概念之后后续的代码才好理解。由于没有称手的工具,就不画图了(其实就是懒T_T).百度上一大堆。
一、netty4.x.x线程模型
Netty4.x.x主要靠两个Reactor(事件驱动)线程组(线程池)维持工作,一个线程组(parentGroup)负责新连接的创建,一个线程组(childGroup)负责连接创建后新消息的进来之后的消息处理。
起服(绑定端口)时parentGroup就会随机出一个线程创建一个serverSocketChannel,用来绑定监听你需要监听的端口,注册accept(16)事件,监听是否有连接到达。当新连接到达时,创建新的socketChannel,添加完需要的handler之后就丢到childerGroup中去注册read(1)事件,然后再去等待下一个新连接的到达。
Netty的设计是单线程串行化执行逻辑,当Channel有新消息需要处理时,从pipeline中的HeadHandler一直向下调用到末尾的TailHandler。HeadHander和TailHandler是pipeline默认创建的,我们自定义的加工handler是通过addxxx方法插入到HeadHandler与TailHandler中间的。到达自己添加的最后一个handler时就可以把逻辑抛到我们自己程序的业务逻辑线程中去执行了。当你处理完逻辑需要向外发消息时,又会从pipeline中的TailHandler开始往回调直到HeadHandler,加工完消息后发送出消息。
二、启动流程源码分析
Netty的工作始于ServerBootstrap,它是netty的启动辅助类。
1. 创建了ServerBootstrap的对象之后,需要传一些参数到它的方法中,这些参数都是干什么的参考下图,在启动过程中有什么作用稍后再看。
parentGroup线程组一般根据你需要监听的端口创建线程,监听一个端口就设置一个线程就可以了,childerGroup则根据需要设置你想要的线程数,如果不设置的话就默认创建CPU核数*2的线程数。
2. 我们从bind方法开始看,进到实现,这个方法的最终实现在AbstractBoostrap类的doBind(SocketAddress)方法。
方法一开始,就是创建ServerSocketChannel并初始化,然后返回个future我们用来判断是否初始化成功,失败则返回失败原因。之后就是判断channel是不是注册完成,还没完就创建监听器,之后再继续,如果注册完成,则继续进行端口的绑定。
2.1 initAndRegister()方法
这里的创建的Channel就是bootStrap.channel(NioServerSocketChannel.class)这里传进去的NioServerSocketChannel,工厂类是AbstractBootstrap根据channel方法传进的类型通过反射创建的工厂类。
这个channel每绑定一个端口只会创建一个,只用来监听accpet事件。
创建了channel之后就需要对channel进行一些初始化,这个init方法是抽象方法,根据不同的用处有不同的实现。
服务端的实现在ServerBootstrap类中,客户端的实现在Bootstrap中,这里只介绍服务端的init方法。
2.1.1 ServerBootstrap中的init方法
Init方法中有一些设置操作和属性的步骤,这里就不细说,以后有时间再单看看他们。
这里为什么要把Acceptor处理类丢到别的线程去添加呢,好吧,英文注释说了,之所以是要延迟添加处理程序,是为了保证Acceptor是在所有用户自己的处理程序之后被添加。因为所有调用addLast方法添加的handler都会在channel所属执行器(从Group中随机出来的)中去执行handler添加时一些需要处理的逻辑(添加到执行器的执行队列中),再说细点,initChannel()方法会在这过程中调用,所以,把Acceptor丢到执行器队列中去执行是保证了它在最后的位置。
initChannel()方法还有一处被调用的地方,就是channel注册的时候,稍后会讲到。
2.1.2 registe
Channel初始化完成后就要注册了,注册这个Channel处理什么类型的事件。
config().group().register(channel);
group方法返回的就是bootstrap中设置的parentGroup。
register方法调用的是MultithreadEventLoopGroup类的register方法,实现是取出一个执行器(EventLoop),执行EventLoop的register方法。中间经过了SingleThreadEventLoop中的register方法,最终调用的是AbstractUnsafe的register方法。
doRegister()方法只给Channel注册了一个0的操作符,表示只是注册,真正的注册accept事件的操作在pipeline.fireChannelActive()方法中一层层的往下调,最后通过HeadContext的read方法调用到了AbstractNioChannel的doBeginRead方法,NioServerSocketChannel注册accept(16)事件,NioSocketChannel注册read(1)事件.
2.2 初始化和注册说完了之后,就是绑定端口的操作了,这没什么好说的,最终是调用到java原生NIO的API去绑定端口。
3. 到这里,netty的启动工作就完成了,等待连接请求的到来。
最后就是返回的future等待Channel的关闭。
4. 最后在说一下2.1.1中出现的ServerBootstrapAcceptor
前面说的都是NioServerSocketChannel的初始化和注册,而它的工作就是接收新的连接添加玩家自定义加工handler和注册。当有新连接到达时,会触发ServerBootstrapAcceptor的channelRead方法。
以上就是netty整个启动过程中的代码分析,希望以后再来看还能看得明白吧...