ServerBootStrap 启动流程源码

本文深入剖析Netty服务器启动过程,从ServerBootstrap类的构建设计到关键方法如group、channel、option、handler等的详细解释,再到核心的initAndRegister、doBind方法的实现细节,带你全面理解Netty服务器如何高效启动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在这里插入图片描述

0 示例代码

在这里插入图片描述
ServerBooktStrap是服务器的一个启动的辅助类,由于参数很多,因此使用了Builder设计模式。接下来看一下对应的方法。

1 group方法保存Reactor线程池

在这里插入图片描述
对于parentGroup是放在抽象方法里的,原因是客户端(BootStrap)也使用了Reactor线程池,是为了代码的复用,值得注意的是这边可以只建立一个EventLoopGroup来共享使用。

2 channel 方法指定具体Channel类型

原理很简单就是保存了构造器,当真正的使用的时候再去实例化。这里原因也是让客户端BootStrap可以重用。看一下代码:
在这里插入图片描述
在这里插入图片描述

3 option 方法设置参数

该方法用来设置TCP的一些参数。对于服务端主要设置backlog参数(默认是100),该参数指定套接口排队的最大连接个数(分为两个队列:未链接队列【第一次握手入队】和已连接队列【握手完成入队】,当进程调用accept,已连接队列队头出队)。调用option方法,将参数加入到map当中去。方法代码如下
在这里插入图片描述

4 handler 和 childHandler方法保存处理器

 这两个方法是用来注册处理器的。区别是handler方法注册的是NioServerSocketChannel的ChannelPipeline,而childHandler是客户端接入的连接SocketChannel对应的ChannelPipelinem。用一张图更加清晰:

摘自《Netty权威指南》

代码是分别:
在这里插入图片描述
在这里插入图片描述

5 pipline中添加处理器

处理器责任链,向末尾添加处理器。
在这里插入图片描述

6 绑定端口并启动服务器

直接来看一下doBind方法:
在这里插入图片描述

6.1 initAndRegister方法

该方法初始化Selector并将Channel注册到上面(类似原生NIO)。看一下代码:

final ChannelFuture initAndRegister() {
       Channel channel = null;
       try {
           channel = channelFactory.newChannel(); // method0: 反射获取NioServerSocketChannel,其无参构造函数初始化等同于ServerSocketChannel.open()来打开Channel;并且创建NioServerSocketChannelConfig配置类
           init(channel); // method1: 初始化 1.设置socket参数和channel的附加属性; 2. 添加父子handler;
       } catch (Throwable t) {
           // 异常情况
           if (channel != null) {
               // channel can be null if newChannel crashed (eg SocketException("too many open files"))
               channel.unsafe().closeForcibly();
               // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
               return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
           }
           // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
           return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
       }

       ChannelFuture regFuture = config().group().register(channel);  // method2 :注册到Reactor线程池中的多路复用器上
       // 异常情况
       if (regFuture.cause() != null) {
           if (channel.isRegistered()) {
               channel.close();
           } else {
               channel.unsafe().closeForcibly();
           }
       }

       // If we are here and the promise is not failed, it's one of the following cases:
       // 1) If we attempted registration from the event loop, the registration has been completed at this point.
       //    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
       // 2) If we attempted registration from the other thread, the registration request has been successfully
       //    added to the event loop's task queue for later execution.
       //    i.e. It's safe to attempt bind() or connect() now:
       //         because bind() or connect() will be executed *after* the scheduled registration task is executed
       //         because register(), bind(), and connect() are all bound to the same thread.

       return regFuture;
   }
6.1.0 method0 newChannel()方法

该方法在这里实际调用了NioServerSocketChannel的无参构造函数,创建了Channel(与原生NIO编程一样),并记录SelectionKey为OP_ACCEPT并创建config类和DefaultChannelPipeline类。
在这里插入图片描述
在这里插入图片描述

6.1.1 method1 init()方法

该方法被ServerBootStrap重写,主要功能:1. 设置socket参数和channel的附加属性; 2. 添加父子handler(其中ServerBootstrapAcceptor处理器用于接收线程移交客户端channel到工作reactor线程池中)代码如下:

  @Override
     void init(Channel channel) throws Exception {
         final Map<ChannelOption<?>, Object> options = options0(); // 代码设置的TCP参数
         synchronized (options) {
             setChannelOptions(channel, options, logger); // channel的config类中记录所有配置的option参数
         }
 
         final Map<AttributeKey<?>, Object> attrs = attrs0(); // channel的附加属性
         synchronized (attrs) {
             for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                 @SuppressWarnings("unchecked")
                 AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                 channel.attr(key).set(e.getValue());  // 绑定附加属性到channel
             }
         }
 
         ChannelPipeline p = channel.pipeline();
 
         final EventLoopGroup currentChildGroup = childGroup;
         final ChannelHandler currentChildHandler = childHandler;
         final Entry<ChannelOption<?>, Object>[] currentChildOptions;
         final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
         synchronized (childOptions) {
             currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
         }
         synchronized (childAttrs) {
             currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
         }
 
       // 添加AbstractBootStrap中的Handler
         p.addLast(new ChannelInitializer<Channel>() {
             @Override
             public void initChannel(final Channel ch) throws Exception {
                 final ChannelPipeline pipeline = ch.pipeline();
                 ChannelHandler handler = config.handler();
                 if (handler != null) {
                     pipeline.addLast(handler);
                 }
 
             // 添加ServerBootstrapAcceptor处理器
                 ch.eventLoop().execute(new Runnable() {
                     @Override
                     public void run() {
                         pipeline.addLast(new ServerBootstrapAcceptor(
                                 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                     }
                 });
             }
         });
     }
6.1.2 method2 register方法

将channel注册到Reactor线程池里的多路复用器上。

 private void register0(ChannelPromise promise) {
            try {
                // check if the channel is still open as it could be closed in the mean time when the register
                // call was outside of the eventLoop
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                doRegister();// 将当前(NioServerSocketChannel)注册到eventLoop中的多路复用器上
                neverRegistered = false;
                registered = true;

                // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
                // user may already fire events through the pipeline in the ChannelFutureListener.
                pipeline.invokeHandlerAddedIfNeeded(); // handlerAdd

                safeSetSuccess(promise);
                pipeline.fireChannelRegistered(); // 触发channel注册,执行处理器的channelRegistered方法
                // Only fire a channelActive if the channel has never been registered. This prevents firing
                // multiple channel actives if the channel is deregistered and re-registered.
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive(); // 触发channel active,执行处理器的channelActive 方法吧                                                                                                                                                                                                                                                                                           
                    } else if (config().isAutoRead()) {
                        // This channel was registered before and autoRead() is set. This means we need to begin read
                        // again so that we process inbound data.
                        //
                        // See https://github.com/netty/netty/issues/4805
                        beginRead(); // 设置selectionKey.interestOps(interestOps|readInterestOp);其中readInterestOp这边是OP_ACCEPT 
                    }
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }

6.2 doBind0 方法

该方法主要是对channel 绑定promise,并启动reactor线程池。代码如下:
在这里插入图片描述
如有错误请指正,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值