文章目录
推荐阅读:
【01】Netty从0到1系列之I/O模型
【02】Netty从0到1系列之NIO
【03】Netty从0到1系列之Selector
【04】Netty从0到1系列之Channel
【05】Netty从0到1系列之Buffer(上)
【06】Netty从0到1系列之Buffer(下)
【07】Netty从0到1系列之零拷贝技术
【08】Netty从0到1系列之整体架构、入门程序
【09】Netty从0到1系列之EventLoop
【10】Netty从0到1系列之EventLoopGroup
【11】Netty从0到1系列之Future
【12】Netty从0到1系列之Promise
【13】Netty从0到1系列之Netty Channel
【14】Netty从0到1系列之ChannelFuture
【15】Netty从0到1系列之CloseFuture
一、Netty Handler
网络处理的核心组件
1.1 Handler是什么?
Handler 是 Netty 框架中的核心处理组件,负责处理所有的 I/O 事件、业务逻辑和协议转换。它采用了责任链模式,允许开发者将多个 Handler 组织成一个处理流水线(Pipeline),每个 Handler 专注于完成特定的功能。
Handler 的核心特性:
- 模块化设计:每个 Handler 只关注单一职责
- 灵活组合:可以通过 Pipeline 自由组合多个 Handler
- 双向处理:支持入站(Inbound)和出站(Outbound)处理
- 线程安全:正确设计下可以保证线程安全
- 生命周期管理:提供完整的生命周期回调
1.2 Handler的继承体系与类型
1.2.1 继承结构
ChannelHandler
-> ChannelInboundHandler (处理入站事件和数据)
-> ChannelInboundHandlerAdapter
-> SimpleChannelInboundHandler
-> ChannelOutboundHandler (处理出站事件和数据)
-> ChannelOutboundHandlerAdapter
-> ChannelDuplexHandler (同时处理入站和出站)
为了更好地理解 Handler 在 Netty 架构中的工作方式,请看下面的流程图:
1.2.2 Handler体系全景图
🌟 核心思想:
- “事件驱动 + 责任链模式” —— 每个
Handler是一个处理节点,形成ChannelPipeline,事件在其中流动。
1.2.3 Handler分类
Netty 的 Handler 主要分为两大类,各自处理不同方向的事件:
- ChannelInboundHandler:处理入站事件,如接收数据、连接建立等
- ChannelOutboundHandler:处理出站事件,如发送数据、关闭连接等
- ChannelDuplexHandler:双向处理器,既可处理入站事件也可处理出站事件
1.2.4 责任链模式
Netty 的 Handler 采用责任链模式组织,形成一个 Pipeline(管道):
- 特点
- 入站事件按 Handler 【添加顺序传播】
- 出站事件按 Handler
【添加逆序传播】- 每个 Handler 可以决定是否将事件传递给下一个 Handler
- 可以动态添加或移除 Handler
1.3 常用Handler接口与实现类
Netty 提供了丰富的 Handler 接口和实现类,满足不同场景需求:
主要实现类说明:
- ChannelInboundHandlerAdapter:入站 Handler 适配器,提供默认实现
- ChannelOutboundHandlerAdapter:出站 Handler 适配器
- SimpleChannelInboundHandler:简化的入站 Handler,自动释放消息
- ChannelDuplexHandler:双向 Handler 基类
- ChannelInitializer:特殊的 Handler,
用于初始化新连接的 Pipeline
1.4 Handler核心接口
1.4.1 ChannelHandler
所有处理器的顶级接口,定义了生命周期方法:
public interface ChannelHandler {
// 添加到 Pipeline 时调用
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
// 从 Pipeline 移除时调用
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
// 标记该 Handler 可以被多个 Channel 共享
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// 标记后,同一个 Handler 实例可被多个 Channel 使用
}
}
1.4.2 ChannelInboundHandler:处理入站事件
处理从网络流入的数据和事件:
public interface ChannelInboundHandler extends ChannelHandler {
// Channel 激活(连接建立)
void channelActive(ChannelHandlerContext ctx) throws Exception;
// Channel 不活跃(连接断开)
void channelInactive(ChannelHandlerContext ctx) throws Exception;
// 接收到数据
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
// 数据读取完成
void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
// 用户事件触发(如心跳)
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;
// 异常发生
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
1.4.3 ChannelOutboundHandler:处理出站事件
处理向外发送的数据和操作:
public interface ChannelOutboundHandler extends ChannelHandler {
// 绑定本地地址
void bind(ChannelHandlerContext ctx, SocketAddress localAddress,
ChannelPromise promise) throws Exception;
// 连接远程地址
void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
SocketAddress localAddress, ChannelPromise promise) throws Exception;
// 写数据
void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;
// 刷新缓冲区
void flush(ChannelHandlerContext ctx) throws Exception;
}
1.4.4 ChannelDuplexHandler:全双工处理器
同时处理入站和出站事件,是 Inbound 和 Outbound 的组合。
1.4.5 Netty Handler层次结构示例
package cn.tcmeta.handler;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import java.util.concurrent.TimeUnit;
public class HandlerHierarchyExample {
// 自定义入站Handler,继承自ChannelInboundHandlerAdapter
static class CustomInboundHandler extends ChannelInboundHandlerAdapter {
private final String name;
public CustomInboundHandler(String name) {
this.name = name;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
String message = in.toString(CharsetUtil.UTF_8);
System.out.println(name + " 收到消息: " + message);
// 将消息传递给下一个入站Handler
ctx.fireChannelRead(msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(name + " 连接激活");
super.channelActive(ctx);
}
}
// 自定义出站Handler,继承自ChannelOutboundHandlerAdapter
static class CustomOutboundHandler extends ChannelOutboundHandlerAdapter {
private final String name;
public CustomOutboundHandler(String name) {
this.name = name;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof ByteBuf) {
String message = ((ByteBuf) msg).toString(CharsetUtil.UTF_8);
System.out.println(name + " 发送消息: " + message);
}
// 将消息传递给下一个出站Handler
ctx.write(msg, promise);
}
}
// 自定义双向Handler,继承自ChannelDuplexHandler
static class CustomDuplexHandler extends ChannelDuplexHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("双向Handler 收到消息");
super.channelRead(ctx, msg);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("双向Handler 发送消息");
super.write(ctx, msg, promise);
}
}
// 自定义SimpleChannelInboundHandler
static class CustomSimpleInboundHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
String message = msg.toString(CharsetUtil.UTF_8);
System.out.println("SimpleInboundHandler 处理消息: " + message);
// 发送响应
String response = "已收到: " + message;
ctx.writeAndFlush(Unpooled.copiedBuffer(response, CharsetUtil.UTF_8));
}
}
public static void main(String[] args) throws Exception {
// 启动服务器
new Thread(() -> {
try {
startServer();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
// 等待服务器启动
TimeUnit.SECONDS.sleep(1);
// 启动客户端并发送消息
startClient();
}
private static void startServer() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
// 添加入站Handler(按添加顺序执行)
pipeline.addLast(new CustomInboundHandler("入站Handler 1"));
pipeline.addLast(new CustomInboundHandler("入站Handler 2"));
// 添加双向Handler
pipeline.addLast(new CustomDuplexHandler());
// 添加出站Handler(按添加逆序执行)
pipeline.addLast(new CustomOutboundHandler("出站Handler 1"));
pipeline.addLast(new CustomOutboundHandler("出站Handler 2"));
// 添加业务处理Handler
pipeline.addLast(new CustomSimpleInboundHandler());
}
});
b.bind(8080).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private static void startClient() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
// 客户端只添加一个简单的Handler用于发送消息
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
// 连接建立后发送消息
ctx.writeAndFlush(Unpooled.copiedBuffer(
"Hello, Netty Handler!", CharsetUtil.UTF_8));
}
});
}
});
b.connect("localhost", 8080).sync().channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
入站Handler 1 连接激活
入站Handler 2 连接激活
入站Handler 1 收到消息: Hello, Netty Handler!
入站Handler 2 收到消息: Hello, Netty Handler!
双向Handler 收到消息
SimpleInboundHandler 处理消息: Hello, Netty Handler!
出站Handler 2 发送消息: 已收到: Hello, Netty Handler!
出站Handler 1 发送消息: 已收到: Hello, Netty Handler!
双向Handler 发送消息
1.5 常用抽象类
✅ ChannelInboundHandlerAdapter, [推荐使用】
- ChannelInboundHandler 的适配器,空实现所有方法,你只需重写关心的方法。
✅ SimpleChannelInboundHandler<T> - 最常用的入站处理器,自动释放消息引用(ReferenceCountUtil.release(msg))。
public abstract class SimpleChannelInboundHandler<I>
extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
boolean release = true;
try {
if (acceptInboundMessage(msg)) {
@SuppressWarnings("unchecked")
I imsg = (I) msg;
channelRead0(ctx, imsg); // 由子类实现
} else {
release = false;
ctx.fireChannelRead(msg); // 传递给下一个 Handler
}
} finally {
if (autoRelease && release) {
ReferenceCountUtil.release(msg); // 自动释放
}
}
}
protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
}
1.6 Handler使用示例
1.6.1 基础 Echo Server(回显服务器)
package cn.tcmeta.handler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets;
/**
* @author: laoren
* @description: Echo服务器
* @version: 1.0.0
*/
@Slf4j
public class NettyEchoServer {
private final int prot;
public NettyEchoServer(int prot) {
this.prot = prot;
}
public void doStart() {
// 1. 创建 EventLoopGroup(线程组)
EventLoopGroup bossGroup = new NioEventLoopGroup(1); // 接受连接
// 如果没有传入线程数量,则默认是cpu个数* 2
EventLoopGroup workerGroup = new NioEventLoopGroup(2); // 处理 I/O
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler())
.addLast(new StringDecoder())
.addLast(new EchoServerHandler());
}
}).childOption(ChannelOption.SO_KEEPALIVE, true);
try {
ChannelFuture future = bootstrap.bind(prot).sync();
log.info("🚀 服务器启动成功,监听端口: {}", prot);
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
log.info("❌ 服务器已关闭 ~~~~");
}
}
// 自定义Handler
private static class EchoServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("🐦🔥 客户端连接: {}", ctx.channel().remoteAddress());
ctx.writeAndFlush("欢迎连接到Echo Server ! \n");
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// 处理数据
log.info("Received: {}", msg);
// 将收到的消息重写发给客户端
ctx.writeAndFlush(Unpooled.copiedBuffer("Echo: " + msg + "\n", StandardCharsets.UTF_8));
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.info("🔌 客户端断开: {}", ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("❌ 发生异常: {}", cause.getMessage());
ctx.close();
}
}
public static void main(String[] args) {
new NettyEchoServer(8080).doStart();
}
}
- 客户端

- 服务器日志
9:47:08 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] REGISTERED
19:47:08 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] ACTIVE
19:47:08 [INFO ] [nioEventLoopGroup-3-2] c.t.h.NettyEchoServer - 🐦🔥 客户端连接: /127.0.0.1:2982
19:47:08 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] WRITE: 欢迎连接到Echo Server !
19:47:08 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] FLUSH
19:47:13 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] READ: 12B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 68 65 6c 6c 6f 20 77 6f 72 6c 64 0a |hello world. |
+--------+-------------------------------------------------+----------------+
19:47:13 [INFO ] [nioEventLoopGroup-3-2] c.t.h.NettyEchoServer - Received: hello world
19:47:13 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] WRITE: 19B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 45 63 68 6f 3a 20 68 65 6c 6c 6f 20 77 6f 72 6c |Echo: hello worl|
|00000010| 64 0a 0a |d.. |
+--------+-------------------------------------------------+----------------+
19:47:13 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] FLUSH
19:47:13 [DEBUG] [nioEventLoopGroup-3-2] i.n.h.l.LoggingHandler - [id: 0x23033458, L:/127.0.0.1:8080 - R:/127.0.0.1:2982] READ COMPLETE
1.6.2 自定义编解码器Handler
- 编码器
/**
* @author: laoren
* @description: 自定义编码器
* @version: 1.0.0
*/
@Slf4j
public class MyStringEncoder extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof ByteBuf) {
log.info("MyStringEncoder --- encoder");
ByteBuf buf = ctx.alloc().buffer();
buf.writeBytes(((String) msg).getBytes(CharsetUtil.UTF_8));
ctx.write(buf, promise);
} else {
// 不是String,直接传递
ctx.write(msg, promise);
}
}
}
- 解码器
/**
* @author: laoren
* @description: 解码器
* @version: 1.0.0
*/
@Slf4j
public class MyStringDecoder extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof ByteBuf buf) {
log.info("MyStringDecoder --- decoder");
String str = buf.toString(io.netty.util.CharsetUtil.UTF_8);
ctx.fireChannelRead(str);
}else {
ctx.fireChannelRead(msg); // 如果不是字符串,则直接传递
}
}
}
- 使用
package cn.tcmeta.handler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
/**
* @author: laoren
* @description: 使用自定义编码、解码器
* @version: 1.0.0
*/
@Slf4j
public class CustomEchoServer {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup(2);
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LoggingHandler())
.addLast(new MyStringEncoder())
.addLast(new MyStringDecoder());
}
}).childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = bootstrap.bind(8080).sync();
log.info("Server started at port 8080");
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
服务端日志输出:
20:03:55 [INFO ] [main] c.t.h.CustomEchoServer - Server started at port 8080
20:04:13 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x582a339d, L:/127.0.0.1:8080 - R:/127.0.0.1:3315] REGISTERED
20:04:13 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x582a339d, L:/127.0.0.1:8080 - R:/127.0.0.1:3315] ACTIVE
20:04:22 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x582a339d, L:/127.0.0.1:8080 - R:/127.0.0.1:3315] READ: 6B
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 68 65 6c 6c 6f 0a |hello. |
+--------+-------------------------------------------------+----------------+
20:04:22 [INFO ] [nioEventLoopGroup-3-1] c.t.h.MyStringDecoder - MyStringDecoder --- decoder
20:04:22 [DEBUG] [nioEventLoopGroup-3-1] i.n.h.l.LoggingHandler - [id: 0x582a339d, L:/127.0.0.1:8080 - R:/127.0.0.1:3315] READ COMPLETE
1.6.3 出站Handler【记录日志】
/**
* @author: laoren
* @description: 日志记录出站Handler
* @version: 1.0.0
*/
@Slf4j
public class LoggingOutboundHandler extends ChannelDuplexHandler {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
log.info(" 📩 准备发送数据: {}", msg);
super.write(ctx, msg, promise);
}
@Override
public void flush(ChannelHandlerContext ctx) throws Exception {
log.info(" 🆕 刷新缓冲区!");
super.flush(ctx);
}
}
1.6.4 使用 SimpleChannelInboundHandler
package cn.tcmeta.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.ReferenceCountUtil;
// 泛型指定处理的消息类型,自动释放资源
public class TypedMessageHandler extends SimpleChannelInboundHandler<String> {
private int messageCount = 0;
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
// 只处理String类型的消息,自动释放资源
messageCount++;
System.out.println("收到第 " + messageCount + " 条消息: " + msg);
// 业务处理逻辑
String response = processMessage(msg);
// 发送响应
ctx.writeAndFlush(response);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("通道激活: " + ctx.channel().remoteAddress());
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("通道关闭,总共处理消息: " + messageCount);
super.channelInactive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.err.println("消息处理异常: " + cause.getMessage());
ctx.close();
}
private String processMessage(String message) {
// 简单的业务逻辑处理
if ("ping".equalsIgnoreCase(message)) {
return "pong";
} else if ("time".equalsIgnoreCase(message)) {
return "当前时间: " + System.currentTimeMillis();
} else {
return "回声: " + message;
}
}
}
1.7 底层实现原理剖析
1.7.1 ✅ ChannelPipeline 与事件传播
Handler 通过 ChannelPipeline 组织成责任链,数据在链中传递:
// 简化的Pipeline实现原理
public class DefaultChannelPipeline implements ChannelPipeline {
// 处理器链的头尾指针
private final AbstractChannelHandlerContext head;
private final AbstractChannelHandlerContext tail;
// 添加处理器
@Override
public ChannelPipeline addLast(String name, ChannelHandler handler) {
// 创建处理器上下文
AbstractChannelHandlerContext newCtx = newContext(name, handler);
// 添加到链尾
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
return this;
}
// 事件传播
private void invokeChannelRead(Object msg) {
// 从头节点开始传播事件
AbstractChannelHandlerContext ctx = head;
while (ctx != null) {
if (ctx.isInbound()) { // 只传播给入站处理器
ctx.invokeChannelRead(msg);
}
ctx = ctx.next;
}
}
}
// 处理器上下文,维护处理器之间的关系
class AbstractChannelHandlerContext implements ChannelHandlerContext {
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
private final ChannelHandler handler;
// 调用处理器的channelRead方法
void invokeChannelRead(Object msg) {
try {
((ChannelInboundHandler) handler).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
// 将事件传播给下一个处理器
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
AbstractChannelHandlerContext next = findContextInbound();
next.invokeChannelRead(msg);
return this;
}
}
- Pipeline 是 Handler 的双向链表
- 入站事件:fireChannelRead() 从 Head 向 Tail 传播
- 出站事件:write() 从 Tail向 Head 传播
1.7.2 Handler线程模型
Handler 的执行与 EventLoop 紧密相关,遵循重要的线程规则:
public class ThreadAwareHandler extends ChannelInboundHandlerAdapter {
private volatile Thread handlerThread;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 记录处理线程
if (handlerThread == null) {
handlerThread = Thread.currentThread();
}
// 检查是否在正确的线程中执行
if (ctx.executor().inEventLoop()) {
System.out.println("在EventLoop线程中执行: " + Thread.currentThread().getName());
processMessage(msg);
} else {
System.err.println("警告:在非EventLoop线程中执行!");
// 应该提交到正确的EventLoop中执行
ctx.executor().execute(() -> processMessage(msg));
}
}
private void processMessage(Object msg) {
// 模拟消息处理
try {
Thread.sleep(100); // 模拟耗时操作
System.out.println("处理消息: " + msg);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("Handler被添加到Pipeline");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("Handler从Pipeline中移除");
}
}
1.7.2 ✅ ChannelHandlerContext
- 每个
Handler在Pipeline中都有一个对应的Context - 用于事件传播和资源访问
- 调用
ctx.fireChannelRead()表示传递给下一个 Handler - 调用
ctx.write()表示从当前节点开始向前传播
1.7.3 ✅ 内存管理与引用计数
- Netty 使用 ByteBuf 实现零拷贝
- SimpleChannelInboundHandler自动释放 msg
- 手动处理时需调用 ReferenceCountUtil.release(msg)
1.8 实践经验与最佳实践
1.8.1 Handler 设计与使用最佳实践
package cn.tcmeta.handler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import java.util.concurrent.atomic.AtomicLong;
// 使用@Sharable注解标记可共享的Handler(必须是线程安全的)
@ChannelHandler.Sharable
public class BestPracticeHandler extends ChannelInboundHandlerAdapter {
// 使用原子变量保证线程安全
private final AtomicLong messageCounter = new AtomicLong(0);
private final AtomicLong totalBytes = new AtomicLong(0);
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
long count = messageCounter.incrementAndGet();
if (msg instanceof String) {
String message = (String) msg;
totalBytes.addAndGet(message.getBytes().length);
// 业务处理逻辑
String result = processBusinessLogic(message);
// 发送响应
ctx.writeAndFlush(result);
// 每100条消息打印一次统计信息
if (count % 100 == 0) {
System.out.println("已处理 " + count + " 条消息,总字节数: " + totalBytes.get());
}
} else {
// 无法处理的消息类型,传递给下一个Handler
ctx.fireChannelRead(msg);
}
} finally {
// 确保释放资源
ReferenceCountUtil.release(msg);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 分类处理不同类型的异常
if (cause instanceof java.io.IOException) {
System.err.println("网络IO异常: " + cause.getMessage());
// 网络异常通常直接关闭连接
ctx.close();
} else if (cause instanceof IllegalArgumentException) {
System.err.println("协议解析异常: " + cause.getMessage());
// 协议异常可以发送错误响应
ctx.writeAndFlush("ERROR: " + cause.getMessage());
} else {
System.err.println("未知异常: " + cause.getMessage());
// 其他异常记录日志并关闭连接
ctx.close();
}
}
// 业务逻辑处理方法
private String processBusinessLogic(String message) {
// 模拟业务处理
if (message == null || message.isEmpty()) {
throw new IllegalArgumentException("消息不能为空");
}
// 简单的回声服务
return "ECHO: " + message;
}
// 获取统计信息
public long getMessageCount() {
return messageCounter.get();
}
public long getTotalBytes() {
return totalBytes.get();
}
// 重置统计信息
public void resetStatistics() {
messageCounter.set(0);
totalBytes.set(0);
}
}
// 高性能的Handler,避免阻塞操作
class HighPerformanceHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 快速处理或提交到业务线程池
if (canProcessFast(msg)) {
processFast(msg);
} else {
// 耗时操作提交到业务线程池
BusinessExecutor.submit(() -> {
try {
Object result = processSlowly(msg);
// 将结果写回EventLoop线程
ctx.executor().execute(() -> {
ctx.writeAndFlush(result);
});
} catch (Exception e) {
ctx.executor().execute(() -> {
ctx.fireExceptionCaught(e);
});
}
});
}
}
private boolean canProcessFast(Object msg) {
// 判断是否能够快速处理
return msg instanceof String && ((String) msg).length() < 1024;
}
private void processFast(Object msg) {
// 快速处理逻辑
}
private Object processSlowly(Object msg) {
// 耗时处理逻辑
try {
Thread.sleep(1000); // 模拟耗时操作
return "Processed: " + msg;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
// 业务线程池
class BusinessExecutor {
private static final java.util.concurrent.ExecutorService executor =
java.util.concurrent.Executors.newFixedThreadPool(10);
public static void submit(Runnable task) {
executor.submit(task);
}
}
1.8.2 Handler生命周期管理
package cn.tcmeta.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
public class LifecycleAwareHandler extends ChannelInboundHandlerAdapter {
// 使用AttributeKey在Channel上存储状态
private static final AttributeKey<SessionState> SESSION_KEY =
AttributeKey.valueOf("sessionState");
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("Handler被添加到Pipeline: " + ctx.name());
// 初始化会话状态
ctx.channel().attr(SESSION_KEY).set(new SessionState());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("Handler从Pipeline移除: " + ctx.name());
// 清理资源
SessionState state = ctx.channel().attr(SESSION_KEY).getAndSet(null);
if (state != null) {
state.cleanup();
}
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("Channel注册到EventLoop");
super.channelRegistered(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("Channel从EventLoop注销");
super.channelUnregistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Channel激活: " + ctx.channel().remoteAddress());
// 会话开始
SessionState state = ctx.channel().attr(SESSION_KEY).get();
state.setStartTime(System.currentTimeMillis());
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Channel关闭");
// 会话结束
SessionState state = ctx.channel().attr(SESSION_KEY).get();
if (state != null) {
long duration = System.currentTimeMillis() - state.getStartTime();
System.out.println("会话持续时间: " + duration + "ms");
}
super.channelInactive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 更新会话状态
SessionState state = ctx.channel().attr(SESSION_KEY).get();
state.incrementMessageCount();
System.out.println("收到第 " + state.getMessageCount() + " 条消息");
ctx.fireChannelRead(msg);
}
// 会话状态类
private static class SessionState {
private long startTime;
private long messageCount;
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getMessageCount() {
return messageCount;
}
public void incrementMessageCount() {
messageCount++;
}
public void cleanup() {
// 清理资源
System.out.println("清理会话资源,总消息数: " + messageCount);
}
}
}
1.9 最佳实践与常见陷阱
1.9.1 ✅ 推荐实践
| 实践 | 说明 |
|---|---|
优先使用 SimpleChannelInboundHandler | 自动释放资源,避免内存泄漏 |
使用 @Sharable 标记无状态 Handler | 提高性能,减少对象创建 |
在 exceptionCaught 中关闭连接 | 防止资源泄漏 |
| 避免在 Handler 中阻塞 | 如 Thread.sleep() |
| 合理组织 Pipeline | 解码 -> 业务 -> 编码 |
1.9.2 ⚠️ 常见错误
// ❌ 错误:忘记释放 ByteBuf
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
// ... 处理
// ❌ 忘记 release
}
// ✅ 正确:使用 SimpleChannelInboundHandler 或手动释放
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
// 自动释放
}
1.10 Handler优缺点总结
1.10.1 ✅ 优点
| 优点 | 说明 |
|---|---|
| 高度解耦 | 业务逻辑与网络层分离 |
| 可扩展性强 | 通过 Pipeline 灵活组合 |
| 支持编解码 | 内置丰富编解码器 |
| 线程安全 | 事件在 EventLoop 线程串行执行 |
| 内存高效 | 支持零拷贝和引用计数 |
1.10.2 ❌ 缺点
| 缺点 | 说明 |
|---|---|
| 学习曲线陡峭 | 需理解 Pipeline 和事件传播 |
| 调试复杂 | 事件在多个 Handler 间流动 |
| 内存泄漏风险 | 忘记释放 ByteBuf |
| 过度设计风险 | 简单场景可能过于复杂 |
1.11 总结: Handler的核心价值
| 维度 | 说明 |
|---|---|
| 核心角色 | Netty 业务逻辑的“处理器” |
| 设计模式 | 责任链模式 + 事件驱动 |
| 核心能力 | 处理入站/出站事件、编解码、异常处理 |
| 适用场景 | 所有网络通信场景:RPC、HTTP、WebSocket、MQTT 等 |
| Netty 地位 | 与 EventLoop、Future 并列为三大核心组件 |
1.12 一句话总结
Netty 的 Handler 是网络编程的“大脑”
- 它通过
Pipeline将复杂的网络操作分解为可复用、可组合的处理单元 - 构建高性能、高可维护性网络应用的核心架构模式。
2490

被折叠的 条评论
为什么被折叠?



