Netty源码分析系列之服务端Channel初始化

本文深入解析Netty服务端Channel的初始化过程,特别是NioServerSocketChannel的创建与初始化。从Netty的NioEventLoopGroup、NioEventLoop到Pipeline的构建,阐述服务端启动时如何创建并初始化Channel,以及Pipeline中各个ChannelHandler的添加和作用。最后,文章强调了理解初始化过程对于掌握Netty的重要性,并鼓励读者通过调试源码加深理解。
摘要由CSDN通过智能技术生成

扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,阅读更多Spring源码分析Java并发编程文章。

微信公众号

问题

老规矩,Netty的源码很难、很复杂,为了更快的学懂新的知识,所以还是带着问题来学习源码。
Netty作为一款基于事件驱动的高性能网络框架,其底层实际上仍然使用的是JDK里面的NIO,Netty在JDK的NIO上做了大量优化,以及封装,降低了开发人员使用NIO的难度。

使用JDK原生的NIO进行网络编程时,首先得做两件事:1. 创建以及初始化ServerSocketChannel,2. 将ServerSocketChannel绑定到多路复用器Selector上。既然说Netty对JDK的NIO做了封装,那么在Netty中是什么时候进行这两步操作的呢?(在Netty中服务端的Channel是NioServerSocketChannel)

答案显然就是:在Netty服务端启动的时候进行的。本文接下来就结合源码来看看Netty是如何进行服务端Channel的初始化,关于绑定到Selector的源码分析会发布在下一篇文章中。

组件说明

在看Netty服务端启动流程的源码之前,先来简单介绍下Netty中相关的组件。这些组件很重要,后面会单独针对每一个组件写文章进行详细说明,今天只是先简单介绍一下。

首先是NioEventLoopGroup,看英文名,翻译过来就是一个NIO事件轮询组。可以简单理解为它是一个线程组,它里面包含了一组线程,这些线程后续用来执行客户端的接入、IO数据读写等任务。

NioEventLoop,可以简单理解为它是一个线程,多个NioEventLoop合起来就是一个NioEventLoopGroup。

Pipeline,它是由ChannelHandlerContext类型的元素组成的一个双向链表,ChannelHandlerContext里面包装了一个ChannelHandler。对于服务端而言,每当有新连接接入时,都会通过Pipeline来传播。这个组件十分重要,在实际工作中,使用Netty实现自己自定义的业务逻辑,就是通过修改Pipeline来实现的。

服务端启动

先来看一段服务端启动的demo代码。
Demo

在示例代码中,①~⑤都是为Netty服务端设置一些属性,比较简单。需要额外说明的是第②步。在第②步中,对服务端而言,需要设置channel的类型为NioServerSocketChannel。当调用channle(NioServerSocketChannel.class)方法时,会调用到AbstractBootstrap类的channel()方法,它干的事情就是创建一个一个ReflectiveChannelFactory工厂,并将ReflectiveChannelFactory实例赋值给AbstractBootstrap类的channelFactory属性。

对于ReflectiveChannelFactory而言,它有一个Constructor类型的属性,叫做constructor,它就是后续用来创建Channel的反射构造器。对于此处而言,constructor就是NioServerSocketChannel.class的反射构造器,通过它就能创建出一个NioServerSocketChannel的实例对象。
channel()方法的源码
channel()

ReflectiveChannelFactory构造器的源码
ReflectiveChannelFactory

在第⑥步中,会调用ServerBootstrap的bind()方法,这个方法中传入了一个端口号:8080。从外面看,这个方法及其简单,但是它干的事情非常多。在这个方法中会初始化服务端的channel,注册channel到selector上,然后绑定端口,启动服务端。下面来通过分析它的源码,来看下服务端Channel是如何进行初始化和绑定操作的。

当调用ServerBootstrap.bind(8080)时,会调用到ServerBootstrap.doBind(),下面我简化了一下doBind()方法的源码,只保留了核心代码,如下。
doBind()

在doBind()方法中调用了两个非常重要的方法,一个是initAndRegister()方法,它用来进行Channel的初始化和注册到Selector上的操作;另外一个是doBind0()方法,它用来进行端口号的绑定操作。今天只分析initAndRegister()方法的前半部分。

channel初始化

initAndRegister()的源码如下。
initAndRegister()

在initAndRegister()方法中,会先通过调用channelFactory.newChannel()来创建一个Channle,对于服务端而言,这里创建的就是NioServerSocketChannel。那么它是如何创建的呢?

首先这里的channelFactory就是前面在②处提到的ReflectiveChannelFactory,它里面包含一个属性constructor。这个constructor就是NioServerSocketChannel.class的反射构造器,通过调用constructor.newInstance()方法,就会调用到NioServerSocketChannel类的无参构造方法。NioServerSocketChannel的无参构造方法如下。

public NioServerSocketChannel() {
   
    // DEFAULT_SELECTOR_PROVIDER的值就是SelectorProvider.provider()
    // 先调用newSocket()
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

在无参构造方法中会先调用newSocket()方法,该方法就是通过JDK原生的API创建一个ServerSocketChannel。

private static ServerSocketChannel newSocket(SelectorProvider provider) {
   
    try {
   
        // provider的值就是SelectorProvider.provider();
        // 这里就是直接调用JDK中NIO的原生API,创建ServerSocketChannel
        return provider.openServerSocketChannel(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值