【对话写 Netty 代码的同学,你真的懂 Netty 了吗?(一)】Netty 初始化总览

240 阅读7分钟

写在前面

源码繁杂,代码晦涩难懂,一看就废……我该如何下手源码?本篇文章将带你一起对 Netty 核心源码进行剖析,源码之道,先主后分,希望本文对你在源码的学习上有所帮助。

音频版地址

Netty 初始化流程剖析

首先从会用开始,如果连使用都没有入门那源码就无从谈起。文稿中为大家列出了NettyServer 端的代码

  public class NettyServer {

    public static void main(String[] args) {

        //创建两个线程组bossGroup和workerGroup, 含有的子线程NioEventLoop的个数默认为cpu核数的两倍
        // bossGroup只是处理连接请求 ,真正的和客户端业务处理,会交给workerGroup完成
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(0);

        try {
            // 服务端启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();

            // 链式编程配置参数

            bootstrap.group(bossGroup, workerGroup)
                    //使用NioServerSocketChannel作为服务器的通道实现
                    // 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接。
                    // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            //对workerGroup的SocketChannel设置处理器
                            socketChannel.pipeline().addLast(new MyNettyServerHandler());
                        }
                    });

            System.out.println("netty server start.....");

            //绑定一个端口并且同步, 生成了一个ChannelFuture异步对象,通过isDone()等方法可以判断异步事件的执行情况
            //启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕
            ChannelFuture cf = bootstrap.bind(9000).sync();

            //给cf注册监听器,监听我们关心的事件
            /*cf.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (cf.isSuccess()) {
                        System.out.println("监听端口9000成功");
                    } else {
                        System.out.println("监听端口9000失败");
                    }
                }
            });*/
            //对通道关闭进行监听,closeFuture是异步操作,监听通道关闭
            // 通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
            cf.channel().closeFuture().sync();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

当中最为核心的代码为:

ChannelFuture cf = bootstrap.bind(9000).sync();

bootstrap.bind(port) 究竟做了什么,在深入其源码之前,我想先将整个 Netty 所涉及到的核心类给介绍一下,对总体有个印象,不至于到了流程跟踪的时候连我在调用哪个类的哪个方法都不知道。(没有骨架铺垫直接一股脑陷入流程之中一旦链路过长或者涉及多线程就很容易迷失方向)

下手源码流程前你应该知道的类:

AbstractBootstrap 是一个帮助类,他使得构建 Channel 更加容易。 当不使用 ServerBootstrap 上下文时, bind() 方法对无状态连接(如 UDP)是非常有用的

//AbstractBootstrap is a helper class that makes it easy to bootstrap a Channel. It support method-chaining to provide an easy way to configure the AbstractBootstrap.
//When not used in a ServerBootstrap context, the bind() methods are useful for connectionless transports such as datagram (UDP).

abstract class AbstractBootstrap

ServerBootstrap 是 AbstractBootstrap 的子类,他使得构建 ServerChannel 服务端通道更简单

//Bootstrap sub-class which allows easy bootstrap of ServerChannel
class ServerBootstrap

Bootstrap 使得构建客户端通道更简单,bind() 方法在无状态连接下结合使用更好,对于常规的 TCP 连接,请使用提供的 connect() 方法

//A Bootstrap that makes it easy to bootstrap a Channel to use for clients.
//The bind() methods are useful in combination with connectionless transports such as datagram (UDP). For regular TCP connections, please use the provided connect() methods.
class Bootstrap

ChannelPipeline 是一个处理或者拦截入站事件和出站事件的 通道处理程序 列表。ChannelPipeline 实现了拦截过滤器的高级形式,给用户充足的控制权来控制事件的处理以及每个 ChannelHandler 在 pipeline 中如何进行相互作用。 关于创建 pipeline 每个 channel 都有自己的 pipeline 并且这个创建过程是自动的 关于事件在 pipeline 中的流向如下图 感兴趣的同学可以自行查看官方文档,此处不再赘述 在这里插入图片描述

//A list of ChannelHandlers which handles or intercepts inbound events and outbound operations of a Channel. ChannelPipeline implements an advanced form of the Intercepting Filter  pattern to give a user full control over how an event is handled and how the ChannelHandlers in a pipeline interact with each other.
//Creation of a pipeline
//Each channel has its own pipeline and it is created automatically when a new //channel is created.
//How an event flows in a pipeline
interface ChannelPipeline

DefaultChannelPipeline 默认的 ChannelPipeline 实现,他通常是在创建通道创建时由通道实现创建

//The default ChannelPipeline implementation. It is usually created by a Channel implementation when the Channel is created.
class DefaultChannelPipeline

SingleThreadEventExecutor 实现了 OrderedEventExecutor 接口,它在单个线程中执行所有提交的任务。

//Abstract base class for OrderedEventExecutor's that execute all its submitted tasks in a single thread.
abstract class SingleThreadEventExecutor

SingleThreadEventLoop 实现了 EventLoop 接口,其执行所有已提交的任务在一个线程中

//Abstract base class for EventLoops that execute all its submitted tasks in a single thread.
 abstract class SingleThreadEventLoop

NioEventLoop 是 SingleThreadEventLoop 的实现,它将通道注册到选择器,并在事件循环中进行多路复用。

//SingleThreadEventLoop implementation which register the Channel's to a Selector and so does the multi-plexing of these in the event loop.
class NioEventLoop

AbstractChannel 骨架通道的实现

abstract class AbstractChannel

AbstractNioChannel 使用 基于选择器方法 实现的通道抽象基类。

//Abstract base class for Channel implementations which use a Selector based approach.
class AbstractNioChannel

AbstractNioByteChannel 基于 AbstractNioChannel ,用于在字节上操作的通道。

//AbstractNioChannel base class for Channels that operate on bytes.
abstract class AbstractNioByteChannel
// 其内部类
class NioByteUnsafe extends AbstractNioUnsafe

AbstractNioMessageChannel 基于 AbstractNioChannel ,用于在消息上操作的通道。

//AbstractNioChannel base class for Channels that operate on messages.
abstract class AbstractNioMessageChannel
// 其内部类
class NioMessageUnsafe extends AbstractNioUnsafe

NioUnsafe 是 Channel.Unsafe 的子类 允许处理基础的 SelectableChannel。

//Special Channel.Unsafe sub-type which allows to access the underlying SelectableChannel
interface NioUnsafe

AbstractChannelHandlerContext 抽象通道处理上下文

class AbstractChannelHandlerContext

以上总结一下:

引导器:

  • 引导器抽象类 abstract class AbstractBootstrap
  • 客户端引导器 class Bootstrap extends AbstractBootstrap
  • 服务端引导器 class ServerBootstrap extends AbstractBootstrap

传输管道:

  • 传输管道接口定义 interface ChannelPipeline
  • 默认传输管道实现 class DefaultChannelPipeline

线程池

  • 单个线程线程池 class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor
  • 事件循环器的抽象基类 abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop
  • 实现了多路复用的 Nio 事件循环器 class NioEventLoop extends SingleThreadEventLoop

通道

  • 抽象通道 通道基类 abstract class AbstractChannel extends DefaultAttributeMap implements Channel
  • 抽象 Nio 通道 abstract class AbstractNioChannel extends AbstractChannel
    • public interface NioUnsafe extends Unsafe
  • 抽象 Nio 字节通道 abstract class AbstractNioByteChannel extends AbstractNioChannel
    • protected abstract class AbstractNioUnsafe extends AbstractUnsafe implements NioUnsafe
    • protected class NioByteUnsafe extends AbstractNioUnsafe
  • 抽象 Nio 消息通道 abstract class AbstractNioMessageChannel extends AbstractNioChannel
    • private final class NioMessageUnsafe extends AbstractNioUnsafe

上下文

  • 抽象通道处理上下文 class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint

整体分为以上部分:引导器、传输管道、线程池、通道 以及 上下文引导器 bootstrap 作为总领,用于串联构建整个流程。 传输管道 pipeline 串联所有的自定义 handler 处理逻辑。 线程池 Netty 自定义线程池处理任务。多路复用事件循环。 通道 channel 用户读取传输的数据。 上下文用于在多个 handler 之间传递数据等。

引子(来盘开胃菜)

在了解了上述的类文件后,我们重点看看 NioEventLoop ,直译 NIO 事件循环 概括的说,该类为我们提供了响应处理事件和数据的能力,即 事件监听无尽的自旋 NioEventLoop 线程做的事情其实很简单,我们可以通过下面的图稿进行一个直观的了解。

在这里插入图片描述 对应到源码如下: 在这里插入图片描述

  1. 首先 select() 超时阻塞等待监听已注册的事件触发
  2. processSelectedKeys() 处理产生网络 IO 的 channel 对应事件
  3. runAllTasks() 执行处理任务队列

写在最后

作为 Netty 源码学习的第一部分,本篇属于开胃菜阶段,带你熟悉了一下核心类的组成和职责,对整体设计有一个大概的认识,下篇文章将从主线流程来跟踪源码,感谢可以看到这里,希望文本对你有所帮助。

我是 dying 搁浅 我看了一场 96 小时的电影也没能等来你的点赞关注收藏,我想这不是你不够喜欢我,而是我看的电影不够长……