小白带你认识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);

6136fdde39dcdae00dfcdced2f3ca87fc22.jpg

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

2d1757518a038ba3a7cc5596a09d41ff2a1.jpg

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

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

0c56b1619cf6e16cfdfcdaa2b4acaaa55e1.jpg

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

f64a4256d98b35cbc6700c0218f4fdfe764.jpg

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

753423812e021d6e6568cf3a885ef5449e6.jpg

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

4de80f792fa2a010317e0b0ded931878400.jpg

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

0b933490760ce7e905cf42308d838e92145.jpg

果然是一个map集合。

server.childHandler(new DealNettyServerInitializer());

d28f694bc955e42d755e6d91775bb68221e.jpg

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

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

24da3961e98cd83c0f530d5963d616a4058.jpg

很简单,继续跟进,

05a2e6c40426c1e27ad16a3fdd4320179da.jpg

调用doBind方法,继续跟进:

38f694b03948b6350cd62c91b63e3f115d3.jpg

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

8bdfe10656e8f619a94e56e11e63ffe59c0.jpg

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

1、创建服务端channel:NioServerSocketChannel

2、初始化服务端Channel:NioServerSocketChannel

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

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

下面,一步一步的分析:

1、创建服务端channel:NioServerSocketChannel

75b1bd2005f901707a39e8417bda93a4573.jpg

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

d28f694bc955e42d755e6d91775bb68221e.jpg

还记的ReflectiveChannelFactory的newChannel方法吗?

4517a14b249cb96aa53648f8e6795c86f32.jpg

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

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

35c4750a8d80a3f3e7243d80204d2280fe4.jpg

这个newSocket是做了什么?

b5061a3121406f1f7370ac310027355d980.jpg

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

bd9685fa1fb40ac76b98e4d5caf04e1a1de.jpg

跟进this:

159781d3cee70029eb3c352f6da37710a6f.jpg

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

30f1901b53cabfffa1aaf3d43b61b742de5.jpg

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

da7fbc4f2e7f98052470dd6c3ece8745347.jpg

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

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

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

f7ac284383d835467720b1cafb8c9d7f8bd.jpg

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

11ac9bec236ac1cca03b9a953c90d97fbd0.jpg

d4c844b54209d3922471bcb6135d72162b7.jpg

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

b98dac906280228c63481a87cab767b4d20.jpg

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

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

NioMessageUnsafe的父类是AbstractNioUnsafe。

即:

NioServerSocketChannel -> AbstractNioMessageChannel -> AbstractNioChannel -> AbstractChannel;

NioMessageUnsafe -> AbstractNioUnsafe

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

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

159781d3cee70029eb3c352f6da37710a6f.jpg

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

fb623f640c7ea958b88a012fc3d47267bd1.jpg

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

527974aa3eb36dc6793d491cea3c9063c75.jpg

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

1f63921d14c06dace1128acf5a7f984cc3e.jpg

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

 

2、初始化服务端Channel:NioServerSocketChannel

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

2a95a0d101c06eef6d52c31f78d6afebb66.jpg

进入init方法:

9fe47ead135dce3ba6fdf604f4c2348efef.jpg

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

d6e970dbeb212d8bdf26a4d1c339f7a516a.jpg

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

6d697536ccd06c1523f3fda8ddf7a702dbc.jpg

同理,setChildOptions和setChildAttrs。

270f06a6669359c6a4087e18e91453cc4b4.jpg

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

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

12fb3e5e09227e89614e4c8820b29c7676f.jpg

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

08bad3dd886c650e1cc78d49ecd6d231395.jpg

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

4e53b6037825a9fb08d6f52fd2056574689.jpg

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

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

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

 

转载于:https://my.oschina.net/littlestyle/blog/2877689

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值