← 返回题目列表

Netty 的 Bootstrap 和 ServerBootstrap 是什么?启动引导做了哪些配置?

高频 中等 第 3 / 23 题 更新于 2026/08/03
BootstrapServerBootstrapNetty启动引导

简化版

Bootstrap(客户端)和 ServerBootstrap(服务端)是 Netty 的「启动引导类」——它们用「链式配置」把启动一个 Netty 应用需要的各种组件(线程组、Channel 类型、处理器、参数)组装起来,最后启动。ServerBootstrap(服务端)的核心配置:group(bossGroup, workerGroup)——两个线程组,boss 负责接受连接、worker 负责处理连接的 IO(主从 Reactor 模型);channel(NioServerSocketChannel.class)——用哪种 Channel(NIO/Epoll);childHandler(...)——给每个新连接(客户端 Channel)配置处理器链(ChannelPipeline);option(...) / childOption(...)——设置服务端 Channel 和客户端 Channel 的 TCP 参数(如 SO_BACKLOG、TCP_NODELAY);bind(port)——绑定端口启动。Bootstrap(客户端)类似,但只有一个线程组、用 handler(...) 配处理器、用 connect(host, port) 连接。关键区别ServerBootstrap 有两个线程组(boss+worker)和 childHandler(区分「服务端 Channel」和「连接 Channel」),Bootstrap 只有一个线程组和 handler

详细版

ServerBootstrap vs Bootstrap

维度ServerBootstrap(服务端)Bootstrap(客户端)
线程组group(boss, worker)(两个)group(worker)(一个)
ChannelNioServerSocketChannelNioSocketChannel
处理器childHandler(连接的处理器)handler(连接的处理器)
参数option(服务端)+ childOption(连接)option(连接)
启动bind(port)connect(host, port)
// ServerBootstrap(服务端)
EventLoopGroup bossGroup = new NioEventLoopGroup(1);      // 接受连接
EventLoopGroup workerGroup = new NioEventLoopGroup();     // 处理 IO
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)                        // 两个线程组
     .channel(NioServerSocketChannel.class)                // NIO 服务端 Channel
     .option(ChannelOption.SO_BACKLOG, 128)                // 服务端 Channel 参数
     .childOption(ChannelOption.SO_KEEPALIVE, true)        // 连接 Channel 参数
     .childHandler(new ChannelInitializer<SocketChannel>() {  // 给每个连接配处理器
         protected void initChannel(SocketChannel ch) {
             ch.pipeline().addLast(new MyHandler());
         }
     });
    ChannelFuture f = b.bind(8080).sync();                 // 绑定端口
    f.channel().closeFuture().sync();                      // 等待关闭
} finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();                      // 优雅关闭
}

// Bootstrap(客户端)
Bootstrap b = new Bootstrap();
b.group(new NioEventLoopGroup())                           // 一个线程组
 .channel(NioSocketChannel.class)
 .handler(new MyClientHandler());                          // handler 不是 childHandler
ChannelFuture f = b.connect("localhost", 8080).sync();     // connect 不是 bind

⚠️ ServerBootstrap 最容易混淆的是「handler vs childHandler」和「option vs childOption」——理解它源于服务端有「两种 Channel」。服务端有一个 ServerChannel(如 NioServerSocketChannel 负责「监听端口、接受新连接」,每接受一个客户端连接就产生一个 子 Channel(SocketChannel 负责「和这个客户端通信」。所以:handler(...) 配的是 ServerChannel 自己的处理器(很少用,一般不配)、childHandler(...) 配的是每个新连接(子 Channel)的处理器(这才是你写业务逻辑的地方,最常用);同理 option(...)ServerChannel 的参数(如 SO_BACKLOG 连接队列大小)、childOption(...) 设子 Channel 的参数(如 TCP_NODELAYSO_KEEPALIVE)。记住带 child 的是给「每个客户端连接」的,不带的是给「服务端监听 Channel」的。这也对应了主从 Reactor:boss 处理 ServerChannel(接受连接)、worker 处理子 Channel(IO)。

完整版教学

一、Bootstrap 是什么:启动引导

先理解 Bootstrap 的定位:

启动一个 Netty 应用,需要组装很多组件:
  - 线程组(EventLoopGroup)
  - Channel 类型(NIO/Epoll)
  - 处理器链(ChannelPipeline / ChannelHandler)
  - TCP 参数(各种 ChannelOption)
  - 绑定端口 / 连接地址

Bootstrap(引导类)的作用:
  用"链式配置"把这些组件组装起来,然后启动
  → 是 Netty 应用的"入口"和"装配器"

两种引导类:
  ServerBootstrap:服务端(监听端口、接受连接)
  Bootstrap:客户端(连接服务器)

链式配置风格:
  b.group(...).channel(...).option(...).childHandler(...).bind(...)
  → 每个方法配置一项,返回自身,链式调用
  → 声明式地"描述"要启动的应用长什么样

所以 Bootstrap = Netty 应用的启动装配器(链式配置各组件)

Bootstrap 是「启动引导类」——启动 Netty 应用要组装很多组件(线程组、Channel 类型、处理器链、TCP 参数、端口),Bootstrap 用链式配置把它们组装起来再启动(是 Netty 应用的入口和装配器)。两种:ServerBootstrap(服务端)、Bootstrap(客户端)。链式配置风格(b.group().channel().childHandler().bind(),每个方法配一项返回自身)。理解「Bootstrap 是启动引导类:链式配置组装组件(线程组/Channel/处理器/参数/端口)再启动、是入口和装配器;ServerBootstrap 服务端、Bootstrap 客户端;链式配置声明式描述应用」,就理解了 Bootstrap 的定位。

二、线程组:boss 和 worker

ServerBootstrap 的核心是「两个线程组」——主从 Reactor:

group(bossGroup, workerGroup):两个 EventLoopGroup

bossGroup(主 Reactor):
  负责"接受新连接"(ServerChannel 的 accept 事件)
  通常线程数很少(1 个就够,一个端口一个监听)
  new NioEventLoopGroup(1)

workerGroup(从 Reactor):
  负责"处理连接的 IO"(子 Channel 的读写)
  处理所有客户端连接的数据读写、业务逻辑
  线程数默认 = 2 × CPU 核数
  new NioEventLoopGroup()  // 默认线程数

主从 Reactor 模型:
  boss 接受连接 → 把新连接注册到 worker
  worker 处理这个连接的所有 IO
  → 接受连接和处理 IO 分离,各司其职
  → 一个 boss 线程接连接,多个 worker 线程处理 IO(并发高)

客户端(Bootstrap)只有一个线程组:
  客户端只连接一个/少量服务器,不用接受连接
  → 一个线程组处理连接的 IO 即可
  b.group(new NioEventLoopGroup())

所以服务端两个线程组(boss 接连接、worker 处理 IO)
  = 主从 Reactor(见 reactor-thread-model 题)

ServerBootstrap 的核心是「两个线程组」(主从 Reactor):bossGroup(主 Reactor)负责接受新连接(ServerChannel 的 accept,通常 1 个线程)、workerGroup(从 Reactor)负责处理连接的 IO(子 Channel 读写、业务,默认 2×CPU 核数线程)。主从 Reactor:boss 接受连接→注册到 worker→worker 处理该连接所有 IO(接受连接和处理 IO 分离、各司其职、并发高)。客户端只有一个线程组(不用接受连接)。理解「ServerBootstrap 两个线程组:bossGroup 接受连接(1 个线程)、workerGroup 处理 IO(2×CPU 线程);主从 Reactor(boss 接连接注册到 worker、worker 处理 IO);客户端一个线程组」,就掌握了线程组。

三、Channel 类型

channel(...) 指定用哪种 Channel 实现:

channel(XxxChannel.class):指定 Channel 类型

服务端 Channel:
  NioServerSocketChannel:NIO 的服务端 Channel(跨平台,最常用)
  EpollServerSocketChannel:Linux 的 Epoll 服务端(Linux 上性能更好)

客户端 Channel:
  NioSocketChannel:NIO 客户端
  EpollSocketChannel:Linux Epoll 客户端

NIO vs Epoll:
  NioXxxChannel:基于 Java NIO(跨平台,Windows/Linux/Mac 都能用)
  EpollXxxChannel:基于 Linux 的 epoll(native,只能 Linux,性能更好)
  → Linux 生产环境可用 Epoll(更少 GC、更高性能)
  → 通用/开发用 NIO

Channel 类型和线程组要匹配:
  NioServerSocketChannel + NioEventLoopGroup
  EpollServerSocketChannel + EpollEventLoopGroup
  → 别混用(NIO Channel 配 Epoll 线程组会出错)

所以 channel() 指定 IO 模型的实现(NIO 跨平台 / Epoll Linux 高性能)

channel(...) 指定 Channel 类型:服务端 NioServerSocketChannel(NIO 跨平台最常用)/EpollServerSocketChannel(Linux Epoll 性能更好)、客户端 NioSocketChannel/EpollSocketChannelNIO vs Epoll:NIO 基于 Java NIO(跨平台)、Epoll 基于 Linux epoll(native、只 Linux、性能更好、更少 GC)——Linux 生产可用 Epoll、通用/开发用 NIO。Channel 类型和线程组要匹配(NIO Channel 配 NioEventLoopGroup、别混用)。理解「channel()指定 Channel 类型:NioServerSocketChannel(跨平台)/EpollServerSocketChannel(Linux 高性能);NIO 跨平台 vs Epoll Linux native 性能好;Channel 和线程组要匹配」,就掌握了 Channel 类型。

四、childHandler 与 handler

handlerchildHandler 的区别——服务端两种 Channel:

服务端有"两种 Channel":
  ① ServerChannel(NioServerSocketChannel):
     监听端口、接受连接(一个)
  ② 子 Channel(SocketChannel):
     每个客户端连接一个(接受连接时创建)

对应两种 handler:
  handler(...):配 ServerChannel 自己的处理器
    → 处理"接受连接"这个事件(很少用,一般不配)
  childHandler(...):配"每个新连接(子 Channel)"的处理器
    → 处理和客户端的通信(★ 这才是写业务逻辑的地方,最常用)

childHandler 通常用 ChannelInitializer:
  .childHandler(new ChannelInitializer<SocketChannel>() {
    protected void initChannel(SocketChannel ch) {
      // 给这个新连接配置处理器链(ChannelPipeline)
      ch.pipeline().addLast(new Decoder());
      ch.pipeline().addLast(new BusinessHandler());
    }
  })
  → 每个新连接建立时,initChannel 被调用,配置它的 pipeline

客户端(Bootstrap)只有一种 Channel(连接):
  用 handler(...)(不是 childHandler)
  → 客户端只有一个连接,直接配 handler

所以:
  服务端 childHandler = 给每个客户端连接配处理器(业务逻辑)
  客户端 handler = 给连接配处理器
  记住带 child 的是给"每个连接"的

handler vs childHandler——服务端有两种 ChannelServerChannel(监听/接受连接,一个)子 Channel(每个客户端连接一个)。对应:handler(...) 配 ServerChannel 处理器(处理接受连接,很少用)、childHandler(...) 配每个新连接的处理器(和客户端通信、写业务逻辑的地方、最常用)。childHandler 通常用 ChannelInitializer(每个新连接建立时 initChannel 被调用配置 pipeline)。客户端只有一种 Channel 用 handler。记住带 child 的是给「每个连接」的。理解「服务端两种 Channel:ServerChannel(监听)+子 Channel(每连接);handler 配 ServerChannel(很少用)/childHandler 配每个连接(业务逻辑最常用,用 ChannelInitializer 配 pipeline);客户端用 handler;带 child 是给每个连接的」,就掌握了 handler/childHandler。

五、option 与 childOption

optionchildOption 设置 TCP 参数——也对应两种 Channel:

option(...) 和 childOption(...):设置 ChannelOption(TCP 参数)

option(...):设 ServerChannel 的参数
  SO_BACKLOG:TCP 连接队列大小(等待被 accept 的连接数)
  → 服务端监听相关的参数

childOption(...):设子 Channel(每个连接)的参数
  SO_KEEPALIVE:TCP 保活
  TCP_NODELAY:禁用 Nagle 算法(小包立即发,降低延迟)
  SO_RCVBUF / SO_SNDBUF:收发缓冲区大小
  → 每个客户端连接相关的参数

常用参数:
  SO_BACKLOG(option):连接队列,高并发调大(如 1024)
  TCP_NODELAY(childOption):延迟敏感设 true(小包立即发)
  SO_KEEPALIVE(childOption):长连接保活
  WRITE_BUFFER_WATER_MARK(childOption):写缓冲水位(背压)

同样的规律(带 child 是给连接的):
  option → ServerChannel(监听)
  childOption → 子 Channel(每个连接)

例:
  .option(ChannelOption.SO_BACKLOG, 1024)      // 监听队列
  .childOption(ChannelOption.TCP_NODELAY, true) // 每个连接禁 Nagle

option vs childOption 设 TCP 参数——也对应两种 Channel:option(...) 设 ServerChannel 参数SO_BACKLOG 连接队列大小,监听相关)、childOption(...) 设子 Channel 参数SO_KEEPALIVE 保活、TCP_NODELAY 禁 Nagle 小包立即发降延迟、SO_RCVBUF/SNDBUF 缓冲区,每个连接相关)。常用:SO_BACKLOG(option,高并发调大)、TCP_NODELAY(childOption,延迟敏感设 true)、WRITE_BUFFER_WATER_MARK(背压)。同样规律带 child 是给连接的。理解「option 设 ServerChannel 参数(SO_BACKLOG 连接队列)、childOption 设子 Channel 参数(TCP_NODELAY 禁 Nagle/SO_KEEPALIVE 保活/写缓冲水位);常用 SO_BACKLOG/TCP_NODELAY;带 child 是给连接的」,就掌握了 option/childOption。

六、启动与关闭

bind/connect 启动,shutdownGracefully 关闭:

服务端启动:bind(port)
  ChannelFuture f = b.bind(8080).sync();
  → 绑定端口,返回 ChannelFuture(异步)
  → sync() 等待绑定完成
  f.channel().closeFuture().sync();
  → 等待服务端 Channel 关闭(阻塞主线程,保持服务运行)

客户端启动:connect(host, port)
  ChannelFuture f = b.connect("localhost", 8080).sync();
  → 连接服务器

异步和 ChannelFuture:
  bind/connect 都是异步的,返回 ChannelFuture
  sync():阻塞等待完成
  addListener():注册回调(异步处理结果)

优雅关闭:
  bossGroup.shutdownGracefully();
  workerGroup.shutdownGracefully();
  → 优雅关闭线程组(处理完手头任务再关,见 graceful-shutdown-netty 题)
  → 放在 finally 里保证关闭

完整流程:
  配置(group/channel/childHandler/option)
  → bind/connect 启动
  → 运行(处理连接/请求)
  → shutdownGracefully 关闭

所以 Bootstrap 完整生命周期:配置 → 启动 → 运行 → 优雅关闭

启动与关闭:服务端 bind(port)(绑定端口返回 ChannelFuture、sync() 等待、closeFuture().sync() 保持运行)、客户端 connect(host, port)(连接)。异步:bind/connect 返回 ChannelFuture(sync() 阻塞等待、addListener() 回调)。优雅关闭bossGroup.shutdownGracefully() + workerGroup.shutdownGracefully()(放 finally 保证关闭)。完整流程:配置→bind/connect 启动→运行→shutdownGracefully 关闭。理解「服务端 bind(port)绑定/closeFuture().sync()保持运行、客户端 connect;异步返回 ChannelFuture(sync 等待/addListener 回调);优雅关闭 shutdownGracefully(放 finally);生命周期配置→启动→运行→关闭」,就掌握了启动与关闭。

记忆钩子:「Netty 启动引导:ServerBootstrap(服务端)/Bootstrap(客户端);ServerBootstrap 核心配置:①group(bossGroup 接受连接 1 个线程,workerGroup 处理 IO 2×CPU 线程)=主从 Reactor②channel(NioServerSocketChannel 跨平台/EpollServerSocketChannel Linux 高性能)③★childHandler 给每个连接配处理器(业务逻辑,用 ChannelInitializer 配 pipeline)vs handler 给 ServerChannel(很少用)④option 设 ServerChannel 参数(SO_BACKLOG 连接队列)vs childOption 设子 Channel 参数(TCP_NODELAY/SO_KEEPALIVE)⑤bind(port)启动;Bootstrap 客户端只一个线程组+handler+connect;★带 child 是给每个连接的、不带是给 ServerChannel 监听的;shutdownGracefully 优雅关闭」

七、常见误区与追问

  • 误区:ServerBootstrap 和 Bootstrap 只是名字不同。 有本质区别——ServerBootstrap(服务端)有两个线程组(boss 接受连接 + worker 处理 IO)、用 childHandler 配连接处理器、用 bind 启动;Bootstrap(客户端)只有一个线程组、用 handler 配处理器、用 connect 连接;服务端要区分「监听 Channel」和「连接 Channel」。
  • 误区:handler 和 childHandler 一样。 不一样——handler 配的是 ServerChannel(监听 Channel)自己的处理器(处理接受连接事件,很少用);childHandler 配的是每个新连接(子 Channel)的处理器(和客户端通信、写业务逻辑,最常用);带 child 的是给「每个客户端连接」的。
  • 误区:option 和 childOption 随便用哪个。 对应不同 Channel——option 设 ServerChannel(监听 Channel)的参数(如 SO_BACKLOG 连接队列大小);childOption 设子 Channel(每个连接)的参数(如 TCP_NODELAY、SO_KEEPALIVE);用错了参数设不到正确的 Channel 上、不生效。
  • 误区:boss 线程组要配很多线程。 boss 只负责接受连接(accept),通常 1 个线程就够(一个端口一个监听);worker 才需要多线程(处理所有连接的 IO,默认 2×CPU 核数);boss 配太多线程浪费(accept 不是瓶颈)。
  • 追问:ServerBootstrap 的 boss 和 worker 线程组各负责什么? boss(bossGroup,主 Reactor)负责接受新连接——处理 ServerChannel 的 accept 事件,通常 1 个线程就够;worker(workerGroup,从 Reactor)负责处理连接的 IO——每个客户端连接的数据读写、业务逻辑,默认 2×CPU 核数线程;这就是主从 Reactor 模型:接受连接和处理 IO 分离,boss 接连接后把连接注册给 worker,worker 处理该连接的所有后续 IO。
  • 追问:handler 和 childHandler 的区别是什么? 服务端有两种 Channel:ServerChannel(监听端口、接受连接)和子 Channel(每个客户端连接);handler(…) 配 ServerChannel 自己的处理器(处理接受连接事件,一般不用配);childHandler(…) 配每个新连接(子 Channel)的处理器(和客户端通信、写业务逻辑,通常用 ChannelInitializer 配置连接的 ChannelPipeline,是最常用的);记住带 child 的是给「每个客户端连接」的。
  • 追问:Netty 应用怎么优雅关闭? 调用线程组的 shutdownGracefully()——bossGroup.shutdownGracefully() 和 workerGroup.shutdownGracefully();它会优雅地关闭 EventLoopGroup(停止接受新任务、处理完手头的任务、然后关闭线程);通常放在 finally 块里保证关闭;这样能让正在处理的连接/任务完成,避免直接关闭导致的数据丢失。

八、加强记忆

ServerBootstrap(服务端)和 Bootstrap(客户端)是 Netty 的「启动引导类」——用链式配置组装启动一个 Netty 应用需要的组件ServerBootstrap 核心配置group(bossGroup, workerGroup)——两个线程组,boss 接受连接(主 Reactor,通常 1 个线程)、worker 处理连接 IO(从 Reactor,默认 2×CPU 核数)(主从 Reactor 模型);channel(...)——Channel 类型(NioServerSocketChannel 跨平台最常用、EpollServerSocketChannel Linux 高性能);childHandler(...)——给每个新连接(子 Channel)配处理器链(写业务逻辑的地方,用 ChannelInitializer 配 pipeline,最常用)vs handler(...) 配 ServerChannel(很少用);option(...) 设 ServerChannel 参数(SO_BACKLOG 连接队列)vs childOption(...) 设子 Channel 参数(TCP_NODELAY/SO_KEEPALIVE);bind(port) 绑定端口启动。Bootstrap(客户端):只有一个线程组、用 handler 配处理器、用 connect(host, port) 连接。关键:带 child 的是给「每个客户端连接(子 Channel)」的,不带的是给「服务端监听 Channel(ServerChannel)」的(对应主从 Reactor)。用 shutdownGracefully() 优雅关闭线程组。一句话「ServerBootstrap 启动引导:group(boss 接连接+worker 处理 IO)/channel(NioServerSocketChannel)/childHandler(每个连接配处理器业务逻辑)/option(ServerChannel 参数)vs childOption(连接参数)/bind(port);Bootstrap 客户端一个线程组+handler+connect;带 child 是给每个连接的、不带是给监听 Channel 的」。