Netty——源码解析


JAVA后端开发知识总结(持续更新…)


Netty——源码解析



零、前言

io.netty.example 包下,有很多 Netty 源码案例,可以用来分析。

一、Netty服务器启动源码

  • 源码需要剖析到 Netty 中调用 doBind 方法为止,即追踪到 NioServerSocketChannel 的 doBind。

  • 同时可以追踪到 NioEventLoop 类的 run 方法,它是无限循环,在服务器端运行。

Netty服务器启动逻辑

public final class EchoServer {
       
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
   
        	// 服务端启动引导工具类
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .option(ChannelOption.SO_BACKLOG, 100)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new ChannelInitializer<SocketChannel>() {
   
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
   
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
   
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     
                     p.addLast(new EchoServerHandler());
                 }
             });

            // 通过 bind 启动服务
            ChannelFuture f = b.bind(PORT).sync();

            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();
        } finally {
   
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
  1. NioEventLoopGroup是整个 Netty 的核心对象,bossGroup 用于接受 TCP 请求,它会将请求交给 workerGroup,workerGroup 会获取到真正的连接,然后和连接进行通信,比如读写解码编码等操作。
  2. 创建了一个 ServerBootstrap 对象,它是一个引导类,用于启动服务器和引导整个程序的初始化,它和 ServerChannel 关联。
  3. 调用 group 方法将两个 group 放入了自己的字段中。
  • group() 方法
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
   
		// 调用父类方法
        super.group(parentGroup);
        ...
        // 直接赋值给字段
        this.childGroup = childGroup;
        return this;
}

// super.group()
public B group(EventLoopGroup group) {
   
        ...
        this.group = group;
        return self();
}
  1. 然后添加了一个 Channel,其中参数为一个 Class 对象,引导类将通过这个 Class 对象反射创建 ChannelFactory,然后添加了一些 TCP 的参数。
  2. 添加一个 SocketChannel(不是 ServerSocketChannel)的 handler。
  3. 然后绑定端口并阻塞至连接成功,通过bind启动服务
  4. 最后 main 线程阻塞等待网络服务被关闭。

1.1 NioEventLoopGroup 的创建及 NioEventLoop 的启动执行

  • EventLoopGroup 实现了EventExcutor接口和 ScheduledExecutorService,因此是一个线程池。
  • 本质是创建了 EventExecutor 数组,它也实现了ScheduledExecutorService
  • Executor线程池本质上就是创建多个NioEventLoop时间执行器。
  • NioEventLoop的实现就是NIO中的Selector增强,本质还是Selector,而NioEventLoop是不能创建线程的,因此用到Executor创建线程
  • 线程run方法中会轮询执行selector.select方法和taskqueue里的内容,每个EventLoop对应一个轮询线程

在这里插入图片描述

  1. EventLoopGroup 是事件循环组(线程组),含有多个 EventLoop,可以注册 Channel,用于在事件循环中去进行选择。
  2. new NioEventLoopGroup(1): 1 表示 bossGroup 事件组有 1 个线程可以指定,如果 new NioEventLoopGroup() 会含有默认的cpu核数 * 2个线程。
  • MultithreadEventExecutorGroup 负责创建事件循环组

在这里插入图片描述

  抽象类 MultithreadEventExecutorGroup 的构造方法是 NioEventLoopGroup 真正的构造处,这里可以看成是一个模板方法

// nThreads:使用的线程数
// executor:执行器
// chooserFactory:单例
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
   
        ...
		// 传入 null, 采用 Netty 默认的线程工厂和默认的执行器 ThreadPerTaskExecutor
        if (executor == null) {
   
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
		// 创建 EventExecutor 数组 
        children = new EventExecutor[nThreads];
		// 初始化线程数组
        for (int i = 0; i < nThreads; i ++) {
   
            boolean success = false;
            try {
   
            	// 创建 NioEventLoop
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
   
                ...
            } finally {
   
            	// 如果创建失败,优雅关闭
                if (!success) {
   
                    for (int j = 0; j < i; j ++) {
   
                        children[j].shutdownGracefully();
                    }
                    for (int j = 0; j < i; j ++) {
   
                        EventExecutor e = children[j];
                        try {
   
                            while (!e.isTerminated()) {
   
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
   
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }
		// 根据线程选择工厂创建一个线程选择器
        chooser = chooserFactory.newChooser(children);
		...
		// 为每一个单例线程池添加一个关闭监听器
        for (EventExecutor e: children) {
   
            e.termination
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值