小白带你认识netty(二)之netty服务端启动(上)

上一章 中的标准netty启动代码中,ServerBootstrap究竟是如何启动的呢?这一章咱们来瞅下。java

server.group(bossGroup, workGroup);
			server.channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100);
			server.childHandler(new DealNettyServerInitializer());
			

			ChannelFuture future = server.bind(7878).sync();

启动代码无非这么几行,我一行一行的瞅。服务器

server.group(bossGroup, workGroup);socket

还记得上一章定义的两个NioEventLoopGroup不?bossGroup和workGroup。这里的ServerBootstrap的group方法就是将workGroup直接赋值给了该对象的childGroup。而bossGroup传到了其父类AbstractBootstrap中,进行保存。oop

看到这,咱们知道了两个类的关系:ServerBootstrap是AbstractBootstrap的子类。this

server.channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100);spa

会将NioServerSocketChannel的class对象做为参数构建ReflectiveChannelFactory对象。这是什么对象呢?进去看一下:.net

哦,原来是一个经过反射构建对象的工厂类。回到上一步,netty会把ReflectiveChannelFactory对象做为参数调用channelFactory()方法。进入这个方法看一下:3d

原来只是保存ReflectiveChannelFactory对象。注意,channel方法是属于AbstractBootstrap对象的,所以,ReflectiveChannelFactory对象是保存在AbstractBootstrap对象中的。rest

一样,option方法也是AbstractBootstrap对象的,options会保存该option对象,那这么说,options应该是一个集合了,netty

果真是一个map集合。

server.childHandler(new DealNettyServerInitializer());

childHandler是属于ServerBootstrap类的,因此将DealNettyServerInitializer对象赋值给了ServerBootstrap的childHandler成员变量。

至此,只是保存变量,没有使用。看下server.bind(7878)方法,此方法就是服务器启动的真正入口。

很简单,继续跟进,

调用doBind方法,继续跟进:

这么多代码,主要是initAndRegister方法,所以跟进去。

下面正式进入启动流程,启动流程大致分为4步:

一、建立服务端channel:NioServerSocketChannel

二、初始化服务端Channel:NioServerSocketChannel

三、注册Selector:将Channel注册到Selector上

四、端口的绑定:服务端端口的监听。

下面,一步一步的分析:

一、建立服务端channel:NioServerSocketChannel

忘了说了,这个bind方法是调用的AbstractBootstrap的方法哦,所以这个channelFactory就是channel()方法的参数ReflectiveChannelFactory,下图为证:

还记的ReflectiveChannelFactory的newChannel方法吗?

很明显,就是经过反射构建NioServerSocketChannel。由于咱们传入的是NioServerSocketChannel的Class对象。

NioServerSocketChannel对象是生成了,咱们一块儿看一下这个NioServerSocketChannel的构造方法吧。

这个newSocket是作了什么?

哦,原来是调用jdk的代码,生成Nio的ServerSocketChannel呀。继续查看:

跟进this:

记住,这里的第三个参数是accept事件,,后续咱们还会提到。跟进父类的构造方法:

咱们能够看到,NioServerSocketChannel的父类是AbstractNioMessageChannel。而后这个构造方法只是继续调用父类的构造方法。

咱们又知道了,AbstractNioMessageChannel的父类是AbstractNioChannel。而且刚才说注意的accept事件,赋值给了AbstractNioChannel的成员变量readInterestOp,后续还会遇到。

注意这个方法,ch是什么?就是传进来的jdk原生的ServerSocketChannel,一次该方法明显是将此通道将被置于非阻塞模式。

继续跟进父类的构造方法:

咱们又知道了AbstractNioChannel的父类是AbstractChannel。而且,在该构造方法中,实例化了id,unsafe和pipeline。

明显此处的NioMessageUnsafe的父类是AbstracNioUnsafe。

到这里,一系列的父类构造方法的调用结束了。咱们先总结下他们之间的关系。

NioServerSocketChannel的父类是AbstractNioMessageChannel;AbstractNioMessageChannel的父类是AbstractNioChannel;AbstractNioChannel的父类是AbstractChannel;还有一个额外的关系

NioMessageUnsafe的父类是AbstractNioUnsafe。

即:

NioServerSocketChannel -> AbstractNioMessageChannel -> AbstractNioChannel -> AbstractChannel;

NioMessageUnsafe -> AbstractNioUnsafe

为啥非要强调这种继承关系?由于后续的调用很复杂,若是不记住他们的关系,很容易分不清楚变量是从何 而来的。。

好了,我再回到开始的NioServerSocketChannel的构造方法上:

看过了super一系列的调用,咱们瞅下下面的代码。先看下javaChannel()干了什么?

调用了父类的javaChannel方法。NioServerSocketChannel的父类是AbstractNioMessageChannel,所以看AbstractMessageNioChannel类的javaChannel方法,咱们发现AbstractMessageNioChannel类中并无javaChannel方法,所以应该调用的是AbstractNioMessageChannel的父类AbstractNioChannel的javaChannel,咱们看一下:

这个ch,不就是以前传入的jdk原声的ServerSocketChannel对象么。。。图下证:

所以javaChannel方法,获取的是原生的ServerSocketChannel对象。点个赞,这个方法的名字真是见名知意呀。那javaChannel().socket()咱们就很容易知道了,就是打开一个socket链接。并将该链接封装到NioServerSocketChannelConfig对象中保存在NioServerSocketChannel的config成员变量上。至此,建立服务端channel:NioServerSocketChannel完成。

 

二、初始化服务端Channel:NioServerSocketChannel

回到initAndRegister方法,看完了NioServerSocketChannel的实例化,咱们看下紧接着的代码init():

进入init方法:

哎呦,这个又一坨代码。。。。不要紧,不少代码都很简单:

上面代码很简单,就是setChannelOptions和setChannelAttrs。

同理,setChildOptions和setChildAttrs。

首先声明下,initChannel方法不是当即被调用的哦,后面会讲到什么时候被调用。总之会被调用,但不是这里。

p是啥,,这个p就是NioServerSocketChannel里成员变量,准确的说是父类父类父类的成员变量,即AbstractChannel的成员变量。下图证:

那个initChannel的方法里的pipeline变量也是p。那pipeline是啥呢?之后会讲的,这里只要知道它是一个双向链表结构就能够了。

所以这段的意思是将handler对象放入到pipeline中。

看到这里,一下懵了,NioServerSocketChannel里面啥时候实例化的EventLoop对象呀?说明下,此刻尚未实例化,由于没有调用该方法,因此暂时不会又null异常。

这段的逻辑就是向pipeline中添加链接器ServerBootstrapAcceptor。

好了,今天先到这,下面两步代码太深,明天再继续吧。最后,必定要记住继承的关系。

相关文章
相关标签/搜索