Netty架构 - NioServerSocketChannel

前言

在解析Netty中的Channel如何应用之前,首先看下如下的代码:
在这里插入图片描述

这段代码,一些使用过netty的朋友们,都蛮了解的。
接下来从server.channel(NioServerSocketChannel.class)这行代码开始本篇文章的解析旅程。

服务端Channel的实例化

概述
设置非阻塞模式,建立NioServerSocketChannel与ServerSocket的关联关系,然后通过ReflectiveChannelFactory完成NioServerSocketChannel的实例化。
在这里插入图片描述

首先看下外层的channelFactory(…)方法做了什么事。
在这里插入图片描述
在这里插入图片描述

很显然是设置ChannelFactory属性为一个ReflectiveChannelFactory实例。

然后看下ReflectiveChannelFactory实例如何构造的。
在这里插入图片描述
在这里插入图片描述

由前文可知,方法的参数,我们传递的是NioServerSocketChannel.class。这里利用反射调用它的无参构造器进行实例化。

在这里插入图片描述

先看下newSocket(…)方法的处理逻辑。
在这里插入图片描述

这里的SelectorProvider,通过在ide工具中debug,我们可以知道实际上是KQueueSelectorProvider。(由SelectorProvider.provider()方法生成)

在这里插入图片描述

可以看出得到的是ServerSocketChannelImpl这个实例,并且将KQueueSelectorProvider作为参数传入。

回到它的构造器方法。
在这里插入图片描述

  • javaChannel():实际上是我们前面看到的ServerSocketChannelImpl
  • socket():构造一个ServerSocket实例。

由此,NioServerSocketChannelConfigNioServerSocketChannelServerSocket与之关联。如同它的名字一样,存储相关的配置。

接着看调用其父类的构造器做了什么事。
在这里插入图片描述

ch.configureBlocking(false)这行代码,可以看出设置非阻塞模式。

接着往下看。
在这里插入图片描述

对parent、id、unsafe、pipeline属性进行赋值。

AbstractBootstrap#initAndRegister()方法有这样一行代码。
在这里插入图片描述

由此,由ReflectiveChannelFactory完成NioServerSocketChannel的实例化。

服务端Channel的初始化

这部分从前言例子的server.bind(port)这行代码开始分析。

概述
将ServerBoostrap#option(…)、attr(…)等方法设置的属性传递给NioServerSocketChannel。然后在DefaultChannelPipeline中添加ServerBootstrap#handler(…)方法定义的ChannelHandler以及ServerBootstrapAcceptor。

bind(…)方法会走到doBind(…)方法,如下:
在这里插入图片描述

重点关注下initAndRegister()方法。(剩余的方法内容会在注册中接着分析)
在这里插入图片描述

  • channelFactory:ReflectiveChannelFactory类型。

在这里插入图片描述

在ServerBootstrap#option(…)方法设置的参数传递给NioServerSocketChannelConfig,也就是NioServerSocketChannel的属性。
在ServerBootstrap#attr(AttributeKey, Object)方法设置的key、value传递给NioServerSocketChannel。

接着看init(…)方法。
在这里插入图片描述

在ServerBootstrap#childGroup(…)、childHandler(…)、childOption(…)以及childAttr(…)方法设置的参数传递给ServerBootstrapAcceptor。

在这里插入图片描述

在DefaultChannelPipeline中,添加了一个ChannelInitializer。其在initChannel(…)方法,定义了在DefaultChannelPipeline中添加ServerBootstrap#handler(…)方法定义的ChannelHandler、以及ServerBootstrapAcceptor实例。

ChannelInitializer,一个特定的ChannelInboundHandler,提供了便捷的方法(也就是initChannel(…)方法)用于初始化一个Channel。
ServerBootstrapAcceptor,同样是一个ChannelInboundHandler。其封装了如下属性:
在这里插入图片描述

服务端Channel的注册

概述
核心是调用nio原生的ServerSocketChannelImpl#register(Selector sel, int ops, Object att)方法,将Netty的NioServerSocketChannel作为attr参数进行传入,从而与nio原生的ServerSocketChannelImpl建立关联性,最后完成Channel在Selector上的注册。

接着AbstractBootstrap#initAndRegister()方法,展开分析,有如下一行代码:
在这里插入图片描述

  • group():ServerBootstrap#group(…)方法指定的NioEventLoopGroup。

在这里插入图片描述

首先看下next()方法,如下:
在这里插入图片描述

这里是调用父类的next()方法,然后进行类型转换。EventLoop是一个ScheduledExecutorService。

在这里插入图片描述

  • chooser:PowerOfTwoEventExecutorChooser类型。

在这里插入图片描述

  • executors:实际上是NioEventLoop数组。

现在,回过头看下register(…)的处理逻辑。

在这里插入图片描述

  • channel:NioServerSocketChannel。
  • this:指代NioEventLoop。

在这里插入图片描述

从register(…)方法中,挑选了如下代码,也就是注册Channel的核心代码。
在这里插入图片描述

接着跟进代码(有省略)。
在这里插入图片描述

  • javaChannel():nio原生的ServerSocketChannelImpl。
  • unwrappedSelector:KQueueSelectorImpl。
  • this:指代NioServerSocketChannel。

可以看出实质上是nio原生方法 - register(Selector sel, int ops, Object att)。将ServerSocketChannelImpl注册到Selector上,同时将Netty的NioServerSocketChannel与之关联。

深入nio的AbstractSelectableChannel#register(…)方法,一看究竟。
在这里插入图片描述

不难看出找到Selector关联的SelectionKey,然后通过SelectionKey#attach(…)方法将NioServerSocketChannel传入,从而建立关联性。