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

上一章 中的标准netty启动代码中,ServerBootstrap到底是如何启动的呢?这一章我们来瞅下。

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);

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第1张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第2张图片

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

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第3张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第4张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第5张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第6张图片

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

d7c9927bf3f04bc685b30813a2fc8ba6.png

果然是一个map集合。

server.childHandler(new DealNettyServerInitializer());

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第7张图片

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

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第8张图片

很简单,继续跟进,

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第9张图片

调用doBind方法,继续跟进:

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第10张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第11张图片

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

1、创建服务端channel:NioServerSocketChannel

2、初始化服务端Channel:NioServerSocketChannel

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

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

下面,一步一步的分析:

1、创建服务端channel:NioServerSocketChannel

8aae8463e3d04d05ed1e3158d506cc5d.png

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第12张图片

还记的ReflectiveChannelFactory的newChannel方法吗?

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第13张图片

很明显,就是通过反射构建NioServerSocketChannel。因为我们传入的是NioServerSocketChannel的Class对象。

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第14张图片

这个newSocket是做了什么?

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第15张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第16张图片

跟进this:

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第17张图片

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

7f4f29bf4946730233ed00c56fd358a8.png

我们可以看到,NioServerSocketChannel的父类是AbstractNioMessageChannel。然后这个构造方法只是继续调用父类的构造方法。

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第18张图片

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

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

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第19张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第20张图片

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第21张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第22张图片

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

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

NioMessageUnsafe的父类是AbstractNioUnsafe。

即:

NioServerSocketChannel -> AbstractNioMessageChannel -> AbstractNioChannel -> AbstractChannel;

NioMessageUnsafe -> AbstractNioUnsafe

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

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第23张图片

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

0ffd081489e1b4a585d94fa22739482e.png

调用了父类的javaChannel方法。NioServerSocketChannel的父类是AbstractNioMessageChannel,因此看AbstractMessageNioChannel类的javaChannel方法,我们发现AbstractMessageNioChannel类中并没有javaChannel方法,因此应该调用的是AbstractNioMessageChannel的父类AbstractNioChannel的javaChannel,我们看一下:

b3b2250cdca0add0c841b387032bd89d.png

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第24张图片

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

2、初始化服务端Channel:NioServerSocketChannel

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

d90543ce376e3ffaf73dc6931a04d7c3.png

进入init方法:

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第25张图片

哎呦,这个又一坨代码。。。。没关系,很多代码都很简单:

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第26张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第27张图片

同理,setChildOptions和setChildAttrs。

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第28张图片

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

p是啥,

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第29张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第30张图片

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

java 启动netty服务_小白带你认识netty(二)之netty服务端启动(上)_第31张图片

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

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

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

你可能感兴趣的:(java,启动netty服务)