Netty4.x.x启动过程源码分析

在分析代码之前不得不先了解下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的对象之后,需要传一些参数到它的方法中,这些参数都是干什么的参考下图,在启动过程中有什么作用稍后再看。

185150_9Ejv_3301501.jpg 

 

parentGroup线程组一般根据你需要监听的端口创建线程,监听一个端口就设置一个线程就可以了,childerGroup则根据需要设置你想要的线程数,如果不设置的话就默认创建CPU核数*2的线程数。

 

2. 我们从bind方法开始看,进到实现,这个方法的最终实现在AbstractBoostrap类的doBind(SocketAddress)方法。

185227_CvwB_3301501.jpg 

方法一开始,就是创建ServerSocketChannel并初始化,然后返回个future我们用来判断是否初始化成功,失败则返回失败原因。之后就是判断channel是不是注册完成,还没完就创建监听器,之后再继续,如果注册完成,则继续进行端口的绑定。

 

2.1 initAndRegister()方法

 

185252_rvmi_3301501.jpg 

这里的创建的Channel就是bootStrap.channel(NioServerSocketChannel.class)这里传进去的NioServerSocketChannel,工厂类是AbstractBootstrap根据channel方法传进的类型通过反射创建的工厂类。

这个channel每绑定一个端口只会创建一个,只用来监听accpet事件。

创建了channel之后就需要对channel进行一些初始化,这个init方法是抽象方法,根据不同的用处有不同的实现。

服务端的实现在ServerBootstrap类中,客户端的实现在Bootstrap中,这里只介绍服务端的init方法。

 

2.1.1 ServerBootstrap中的init方法

Init方法中有一些设置操作和属性的步骤,这里就不细说,以后有时间再单看看他们。

185322_G9Fc_3301501.jpg 

 

这里为什么要把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方法。

185409_MhoK_3301501.jpg 

 

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方法。

185444_Hn0i_3301501.jpg 

 

以上就是netty整个启动过程中的代码分析,希望以后再来看还能看得明白吧...

转载于:https://my.oschina.net/coderljp/blog/856546

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值