Netty 中用了哪些设计模式?


一则或许对你有用的小广告

欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书

  • 《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于 Spring AI + Spring Boot 3.x + JDK 21...查看介绍

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...查看介绍;演示链接:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/

  • 新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍

截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观

面试考察点

  1. 框架理解深度:面试官想看的不是你能背几个模式名字,而是你是不是真的读过 Netty 源码、理解它的架构设计。能答出 "责任链"、"Reactor" 是及格线,能答出策略模式的选择器、装饰器模式的 ByteBuf 才是亮点。

  2. 设计模式落地能力:设计模式是抽象的,但 Netty 是把设计模式落到实处的典型。能不能结合具体类名、方法说出模式的应用场景,直接反映你的工程素养。

  3. 举一反三的能力:懂了 Netty 怎么用设计模式,自己写框架或者设计中间件时,能不能借鉴这些思路。这才是面试官真正想看到的。

核心答案

Netty 几乎是 Java 圈里把设计模式用得最透的网络框架,10 种以上设计模式随便挑。核心的几个列一下:

设计模式 典型应用场景 重要性
Reactor 模式 整体架构(Boss/Worker) ⭐⭐⭐⭐⭐
责任链模式 ChannelPipeline + ChannelHandler ⭐⭐⭐⭐⭐
主从 Reactor EventLoopGroup ⭐⭐⭐⭐⭐
建造者模式 ServerBootstrap / Bootstrap ⭐⭐⭐⭐
工厂模式 ChannelFactoryReflectiveChannelFactory ⭐⭐⭐⭐
策略模式 EventExecutorChooserFactory ⭐⭐⭐⭐
装饰器模式 ByteBuf 体系 ⭐⭐⭐⭐
观察者模式 ChannelFuture + Listener ⭐⭐⭐
适配器模式 ChannelHandlerAdapter 系列 ⭐⭐⭐
模板方法 AbstractChannelAbstractByteBuf ⭐⭐⭐
单例模式 各种 Flyweight、ChannelOption ⭐⭐

下面挑几个最有代表性的深挖一下。

深度解析

一、责任链模式 —— Netty 的灵魂

要说 Netty 用得最经典的设计模式,绝对是责任链。ChannelPipeline 把一堆 ChannelHandler 串成一条链,入站事件从头到尾流,出站事件从尾到头流,每个 Handler 只关心自己那一段逻辑。

Netty ChannelPipeline 责任链模式
Netty ChannelPipeline 责任链模式

上面这条链就是 Netty 处理网络事件的核心流程:

  • 入站事件(读、连接激活)从 HeadContext 往后传,依次经过解码、业务处理
  • 出站事件(写、刷新)从链尾往前传,经过编码后到达 HeadContext,最终由 unsafe 写到 Socket
  • 每个 Handler 既可以让事件继续往下传,也可以直接截断(比如校验失败的 Handler 直接关闭连接)

代码写起来特别清爽,跟 Spring 拦截器、Filter 一个味儿:

// 自定义一个 Handler,往 Pipeline 里一塞就行
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel ch) {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new StringDecoder());       // 解码
        pipeline.addLast(new StringEncoder());       // 编码
        pipeline.addLast(new MyBusinessHandler());   // 业务处理
    }
});

为什么用责任链? 网络协议解析本来就是分层、分步骤的(粘包处理 → 协议解析 → 业务逻辑 → 结果返回),用责任链天生适合。而且每个 Handler 互相解耦,加一个减一个完全不影响别的,扩展性拉满。

二、Reactor 模式 —— 整个 Netty 的骨架

Reactor 模式是 Netty 的核心架构模式。简单说就是:一个或多个线程盯着所有的 IO 事件,事件来了就分发到对应的 Handler 处理。Netty 实现了主从 Reactor 模式:

Netty 主从 Reactor 模式
Netty 主从 Reactor 模式

主从 Reactor 的分工很明确:

  • Boss Group(主 Reactor):专门负责接收客户端的新连接,类似饭店的迎宾
  • Worker Group(从 Reactor):负责处理已建立连接的读写事件,类似服务员
  • 这种分离的好处是:接收连接和处理 IO 互不阻塞,性能天花板更高

底层依赖的就是 Java NIO 的 Selector,Netty 把它包装成了 NioEventLoop,每个 EventLoop 绑一个线程,绑一组 Channel,全程异步非阻塞。

三、建造者模式 —— Bootstrap 的链式 API

new ServerBootstrap()
    .group(bossGroup, workerGroup)
    .channel(NioServerSocketChannel.class)
    .option(ChannelOption.SO_BACKLOG, 128)
    .childHandler(new MyInitializer())
    .bind(8080);

这是典型的建造者模式(虽然严格说是链式 API + Builder 变体)。ServerBootstrap 内部维护一堆参数(group、channel、options、handler……),通过链式调用逐步配置,最后 bind() 才真正构建。配置项多、可选参数多的时候,建造者模式比构造函数堆参数优雅太多。

四、策略模式 —— EventExecutorChooserFactory

这个很多人答不上来,其实是 Netty 一个很巧妙的设计。EventLoopGroup 里有多个 EventLoop,新连接来了该分配给哪个?Netty 用策略模式做了两种选择算法:

// DefaultEventExecutorChooserFactory 中的核心代码
if (isPowerOfTwo(executors.length)) {
    return new PowerOfTwoEventExecutorChooser(executors);
} else {
    return new GenericEventExecutorChooser(executors);
}
  • 线程数是 2 的幂次:用位运算 & (length - 1),性能更好
  • 不是 2 的幂次:用取模 abs(idx++ % length)

这就是典型的策略模式:同一个目标(选一个 EventLoop),根据不同场景用不同算法,对外接口完全一致。

五、装饰器模式 —— ByteBuf 体系

Netty 的 ByteBuf 体系把装饰器模式玩出了花:

  • Unpooled.wrappedBuffer():把多个 ByteBuf 包装成一个,对外像一个整体
  • CompositeByteBuf:逻辑合并,物理上还是多个独立的 ByteBuf,零拷贝的核心(严格说更像组合模式,但常和装饰器一起说)
  • ReadOnlyByteBuf:装饰成只读
  • WrappedByteBuf:各种包装的基类

好处是:你想加什么功能就套一层装饰器,互不干扰,比继承灵活得多。

六、观察者模式 —— ChannelFuture

Netty 所有 IO 操作都是异步的,怎么知道操作完成?观察者模式:

ChannelFuture future = channel.writeAndFlush(msg);
future.addListener(future1 -> {
    if (future1.isSuccess()) {
        System.out.println("发送成功");
    } else {
        future1.cause().printStackTrace();
    }
});

addListener 就是注册观察者,操作完成时回调。比同步阻塞等待优雅太多,这也是异步编程的核心套路。

面试高频追问

  1. 追问一:Netty 的责任链和 Spring 的 Filter 链有什么区别?

    • Netty 的 Pipeline 是双向的,入站和出站分开走;Filter 是单向的。Netty 的 Handler 还能在运行时动态增删,Filter 一般是启动时确定的。
  2. 追问二:为什么 Netty 要自己实现 ByteBuf,不用 JDK 的 ByteBuffer?

    • JDK 的 ByteBuffer 只有一个指针,读写要 flip,特别反人类;ByteBuf 双指针(readerIndex/writerIndex),支持池化、零拷贝、自动扩容,性能和易用性都强得多。
  3. 追问三:主从 Reactor 和单 Reactor 有什么区别?

    • 单 Reactor 一个线程干所有事(接收连接 + 处理 IO),高并发下成为瓶颈;主从 Reactor 拆开,主专门接连接,从处理 IO,吞吐量更高。
  4. 追问四:策略模式的 EventExecutorChooser 为什么不用 if-else 直接写?

    • 解耦。ChooserFactory 只负责 "选哪个策略",具体怎么选交给不同的 Chooser 实现,符合开闭原则,加新算法不用动老代码。

常见面试变体

  • "Netty 的 ChannelPipeline 用了什么设计模式?"
  • "说说 Netty 的 Reactor 模式是怎么实现的?"
  • "Netty 的 ByteBuf 用到了哪些设计模式?"
  • "为什么 Netty 要用建造者模式设计 Bootstrap?"

记忆口诀

五大核心:责任链一条、Reactor 一对(主从)、Builder 配置、策略选择、装饰 ByteBuf。

一句话:Netty = Reactor 骨架 + 责任链管道 + 各种设计模式加持。

总结

答这道题别上来就背模式名,挑三个最能打的深入讲:责任链(Pipeline)+ 主从 Reactor(整体架构)+ 策略/装饰器/建造者(点缀亮点)。配合具体的类名和方法讲,让面试官知道你是真读过源码,不是背的八股。能把每个模式 "解决了什么问题" 说清楚,这道题基本拿满分。