Netty从0到1系列之Netty Pipeline【下】
本文深入剖析了Netty中Pipeline的底层实现原理。Pipeline采用双向链表结构管理ChannelHandler,每个Handler被包装在ChannelHandlerContext中。关键实现包括:通过head和tail虚拟节点构建双向链表;addLast()方法将Handler添加到链表尾部;事件传播机制分为入站(head→tail)和出站(tail→head)两种方向。
文章目录
推荐阅读:
【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
【16】Netty从0到1系列之Netty Handler
【17】Netty从0到1系列之Netty Pipeline【上】
一、Netty Pipeline:责任链模式的核心实现【下】
1.6 Pipeline的底层实现原理
1.6.1 Pipeline 的双向链表结构
Pipeline 内部使用双向链表来管理所有的 ChannelHandler,每个 Handler 都被包装在 ChannelHandlerContext 中:
// Netty简化的 Pipeline 实现原理
public class DefaultChannelPipeline implements ChannelPipeline {
// 头尾虚拟节点(内部类实例)
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
private final Channel channel;
public DefaultChannelPipeline(Channel channel) {
this.channel = channel;
// 创建头尾虚拟节点
tail = new TailContext(this);
head = new HeadContext(this);
// 构建双向链表
head.next = tail;
tail.prev = head;
}
// 添加处理器到链表尾部
@Override
public ChannelPipeline addLast(String name, ChannelHandler handler) {
// 创建新的上下文节点
AbstractChannelHandlerContext newCtx = new DefaultChannelHandlerContext(this, name, handler);
// 添加到链表尾部(tail之前)
synchronized (this) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
// 调用handlerAdded回调
callHandlerAdded0(newCtx);
return this;
}
// 事件传播机制
@Override
public ChannelPipeline fireChannelRead(Object msg) {
// 从头节点开始传播事件
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
}
// Handler 上下文实现
class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {
private final ChannelHandler handler;
volatile DefaultChannelHandlerContext next;
volatile DefaultChannelHandlerContext prev;
// 调用具体Handler的方法
private void invokeChannelRead(Object msg) {
try {
((ChannelInboundHandler) handler).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
}
// 传播事件到下一个Handler
@Override
public ChannelHandlerContext fireChannelRead(Object msg) {
// 找到下一个入站处理器
DefaultChannelHandlerContext next = findContextInbound();
next.invokeChannelRead(msg);
return this;
}
}
addLast()
:将Handler
包装成Context
,插入链表尾部remove()
:从链表中移除Context
- HeadContext:链表头,既是 Inbound 处理器也是 Outbound 处理器
- TailContext:链表尾,默认实现了一些基本的异常处理
- ChannelHandlerContext:处理器上下文,维护了处理器之间的关联关系,提供了事件传播方法
1.6.2 入站和出站的事件传播机制
Pipeline 中的事件传播遵循严格的规则:
-
入站事件 (Inbound)
- 从 Head 向 Tail 方向传播
- 常见事件:channelActive、channelRead、channelReadComplete 等
-
出站事件 (Outbound)
- 从 Tail 向 Head 方向传播
- 常见事件:bind、connect、write、flush 等
// HeadContext - 入站起点和出站终点
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
private final Unsafe unsafe;
// 入站事件:从head开始向后传播
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.fireChannelRead(msg); // 传递给下一个处理器
}
// 出站事件:最终由head处理
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
// 真正执行写入操作
unsafe.write(msg, promise);
}
}
// TailContext - 入站终点和出站起点
final class TailContext extends AbstractChannelHandlerContext
implements ChannelInboundHandler {
// 入站事件终点:处理未消费的消息
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
// 记录未处理的消息
logger.debug("Discarded inbound message: {}", msg);
} finally {
// 释放资源
ReferenceCountUtil.release(msg);
}
}
// 出站事件:从tail开始向前传播
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
// 向前传播write事件
ctx.write(msg, promise);
}
}
🌟 性能关键:
- 所有事件在
EventLoop
线程串行执行,避免锁竞争- 事件传播是方法调用,无线程切换开销
入站事件、出站事件核心代码逻辑【简化版本】:
// 入站事件传播
private AbstractChannelHandlerContext findContextInbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
// 出站事件传播
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
当调用ctx.fireChannelRead(msg)时,Netty 会找到下一个入站处理器并调用其channelRead
方法。
1.6.3 内存管理与资源释放
- TailHandler的 channelRead方法自动调用 ReferenceCountUtil.release(msg)
- SimpleChannelInboundHandler 在
channelRead0
执行后自动释放 - 最佳实践:优先使用
SimpleChannelInboundHandler
1.7 实践经验与最佳实践
1.7.1 实践经验与最佳实践
1. 处理器顺序安排最佳实践
// 1. 处理器顺序安排最佳实践
public static void setupOptimalPipeline(ChannelPipeline pipeline) {
// 顺序很重要!按照处理阶段的逻辑顺序安排
// 第一阶段:协议解析(最前面)
pipeline.addLast("frameDecoder", new CustomFrameDecoder());
pipeline.addLast("protocolDecoder", new CustomProtocolDecoder());
// 第二阶段:安全处理
pipeline.addLast("sslHandler", new SslHandler());
pipeline.addLast("authHandler", new AuthenticationHandler());
// 第三阶段:业务处理
pipeline.addLast("throttlingHandler", new ThrottlingHandler());
pipeline.addLast("businessLogic", new BusinessLogicHandler());
// 第四阶段:统计监控(业务处理后)
pipeline.addLast("metricsHandler", new MetricsHandler());
pipeline.addLast("loggingHandler", new AuditLogHandler());
// 第五阶段:异常处理(最后面)
pipeline.addLast("exceptionHandler", new GlobalExceptionHandler());
}
2. 资源管理最佳实践
// 2. 资源管理最佳实践
@ChannelHandler.Sharable
public static class ResourceAwareHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
if (msg instanceof ByteBuf) {
ByteBuf buf = (ByteBuf) msg;
try {
processMessage(buf);
} finally {
// 确保释放资源
if (buf.refCnt() > 0) {
buf.release();
}
}
} else {
processMessage(msg);
}
} catch (Exception e) {
// 异常处理
ctx.fireExceptionCaught(e);
}
}
private void processMessage(Object msg) {
// 业务逻辑处理
}
}
3. 性能优化实践
public static class HighPerformanceHandler extends ChannelInboundHandlerAdapter {
private static final int BATCH_SIZE = 100;
private int count = 0;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
count++;
// 批量处理优化
if (count % BATCH_SIZE == 0) {
// 批量处理逻辑
ctx.executor().execute(() -> processBatch(msg));
} else {
ctx.fireChannelRead(msg);
}
}
private void processBatch(Object msg) {
// 批量处理实现
}
}
4. 动态Pipeline管理实践
public static class DynamicPipelineManager extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ChannelPipeline pipeline = ctx.pipeline();
// 根据消息类型动态调整Pipeline
if (msg instanceof SpecialMessage) {
// 添加特殊处理器
if (pipeline.get("specialHandler") == null) {
pipeline.addAfter(ctx.name(), "specialHandler", new SpecialHandler());
}
} else {
// 移除特殊处理器
if (pipeline.get("specialHandler") != null) {
pipeline.remove("specialHandler");
}
}
ctx.fireChannelRead(msg);
}
}
1.7.2 高级 Pipeline 管理模式
[!tip]
- Pipeline 模板管理
- 条件处理器执行
- Pipeline 性能监控
import io.netty.channel.*;
import io.netty.util.AttributeKey;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class AdvancedPipelineManagement {
// 1. Pipeline 模板管理
public static class PipelineTemplateManager {
private static final Map<String, List<HandlerDefinition>> templates = new ConcurrentHashMap<>();
public static void registerTemplate(String name, List<HandlerDefinition> handlers) {
templates.put(name, handlers);
}
public static void applyTemplate(ChannelPipeline pipeline, String templateName) {
List<HandlerDefinition> handlers = templates.get(templateName);
if (handlers != null) {
for (HandlerDefinition def : handlers) {
pipeline.addLast(def.name, def.handler);
}
}
}
}
public static class HandlerDefinition {
private final String name;
private final ChannelHandler handler;
public HandlerDefinition(String name, ChannelHandler handler) {
this.name = name;
this.handler = handler;
}
}
// 2. 条件性处理器执行
public static class ConditionalHandler extends ChannelInboundHandlerAdapter {
private final AttributeKey<Boolean> CONDITION_KEY = AttributeKey.valueOf("condition");
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Boolean condition = ctx.channel().attr(CONDITION_KEY).get();
if (condition != null && condition) {
// 执行条件处理逻辑
processConditionally(ctx, msg);
} else {
// 跳过处理,直接传递
ctx.fireChannelRead(msg);
}
}
private void processConditionally(ChannelHandlerContext ctx, Object msg) {
// 条件处理逻辑
}
}
// 3. Pipeline 性能监控
public static class PipelineMonitorHandler extends ChannelInboundHandlerAdapter {
private final Map<String, Long> handlerProcessingTime = new ConcurrentHashMap<>();
private long startTime;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
startTime = System.nanoTime();
ctx.fireChannelRead(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
long totalTime = System.nanoTime() - startTime;
// 记录处理时间
monitorPerformance(totalTime);
ctx.fireChannelReadComplete();
}
private void monitorPerformance(long totalTime) {
// 性能监控逻辑
}
}
}
1.7.3 动态修改 Pipeline
可以在运行时动态添加、删除或替换处理器:
// 动态添加处理器
channel.pipeline().addLast("newHandler", new NewHandler());
// 替换处理器
channel.pipeline().replace("oldHandler", "newHandler", new NewHandler());
// 移除处理器
channel.pipeline().remove("handlerName");
// 移动处理器到指定位置
channel.pipeline().addBefore("existingHandler", "newHandler", new NewHandler());
1.7.4 异常处理
Pipeline 有完善的异常传播机制,异常会沿着处理器链传播,直到被处理或到达 TailContext:
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.err.println("发生异常: " + cause.getMessage());
// 可以选择处理异常或继续传播
// ctx.fireExceptionCaught(cause);
// 重要内容: 【通常发生异常时需要关闭通道】
ctx.close();
}
1.8 🚀 Handler和Pipeline示例
理解一下,出站、入站操作
ChannelHandler 用来处理 Channel 上的各种事件,分为入站、出站两种
。所有 ChannelHandler 被连成一串,就是 Pipeline
- 入站处理器通常是
ChannelInboundHandlerAdapter
的子类,主要用来读取客户端数据,写回结果 - 出站处理器通常是
ChannelOutboundHandlerAdapter
的子类,主要对写回结果进行加工
打个比喻,每个 Channel 是一个产品的加工车间
,Pipeline 是车间中的流水线,ChannelHandler 就是流水线上的各道工序,而后面要讲的 ByteBuf 是原材料,经过很多工序的加工:先经过一道道入站工序,再经过一道道出站工序最终变成产品
如下示例代码:
package cn.tcmeta.pipeline;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class PipeLineTestServer {
public static void main(String[] args) {
ChannelFuture channelFuture = new ServerBootstrap()
.group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline()
.addLast("handler1", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler1 读取到消息: " + msg);
ctx.fireChannelRead(msg);
}
});
ch.pipeline()
.addLast("handler2", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler2 读取到消息: " + msg);
ctx.fireChannelRead(msg);
}
});
ch.pipeline()
.addLast("handler3", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler3 读取到消息: " + msg);
ctx.channel().write(msg);
}
});
ch.pipeline().addLast("handler4", new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler4 写入到消息: " + msg);
ctx.write(msg, promise);
}
});
ch.pipeline().addLast("handler5", new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler5 写入到消息: " + msg);
ctx.write(msg, promise);
}
});
ch.pipeline().addLast("handler6", new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler6 写入到消息: " + msg);
System.out.println(ch.pipeline().names());
ctx.write(msg, promise);
}
});
}
}).bind("127.0.0.1", 8080);
System.out.println( "[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "channel: " + channelFuture);
System.out.println( "[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "服务端启动成功 ~~~~ listening port : 8080");
}
}
整理一下代码:
// 1. ChannelInboundHandlerAdapter -- 入站操作
ch.pipeline()
.addLast("handler1", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler1 读取到消息: " + msg);
ctx.fireChannelRead(msg);
}
});
// 2. ChannelInboundHandlerAdapter -- 入站操作
ch.pipeline()
.addLast("handler2", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler2 读取到消息: " + msg);
ctx.fireChannelRead(msg);
}
});
// 3. ChannelInboundHandlerAdapter -- 入站操作
ch.pipeline()
.addLast("handler3", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler3 读取到消息: " + msg);
ctx.channel().write(msg);
}
});
// 4. ChannelInboundHandlerAdapter -- 出站操作
ch.pipeline().addLast("handler4", new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler4 写入到消息: " + msg);
ctx.write(msg, promise);
}
});
// 5. ChannelInboundHandlerAdapter -- 出站操作
ch.pipeline().addLast("handler5", new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler5 写入到消息: " + msg);
ctx.write(msg, promise);
}
});
// 6. ChannelInboundHandlerAdapter -- 出站操作
ch.pipeline().addLast("handler6", new ChannelOutboundHandlerAdapter(){
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler6 写入到消息: " + msg);
System.out.println(ch.pipeline().names());
ctx.write(msg, promise);
}
});
客户端测试:
C:\Users\ldcig>nc localhost 8080
hello
服务器端日志输出:
[main] --- : channel: AbstractBootstrap$PendingRegistrationPromise@1de76cc7(incomplete)
[main] --- : 服务端启动成功 ~~~~ listening port : 8080
[nioEventLoopGroup-3-1] --- handler1 读取到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[nioEventLoopGroup-3-1] --- handler2 读取到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[nioEventLoopGroup-3-1] --- handler3 读取到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[nioEventLoopGroup-3-1] --- handler6 写入到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[handler1, handler2, handler3, handler4, handler5, handler6, DefaultChannelPipeline$TailContext#0]
[nioEventLoopGroup-3-1] --- handler5 写入到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[nioEventLoopGroup-3-1] --- handler4 写入到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
结果分析:
ch.pipeline.names()
结果:
在实现操作当中,自动会添加一个head、tail的channelHandler, 即:
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
- ctx.channel.write(msg)和ctx.write(msg,promise), 触发写操作的时候, 则会进行【出站】操作
- ctx.channel.write(msg)是从
tail
开始查找,按照出站顺序执行- ctx.write(msg) / ctx.write(msg, promise), 从当前的handler向前查找, 依次执行
ch.pipeline()
.addLast("handler3", new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("[" + Thread.currentThread().getName() + "]" + " --- \t\t: " + "handler3 读取到消息: " + msg);
// 从链表尾部,找出站处理器,依次从后往前执行
// ctx.channel().write(msg);
// System.out.println(ctx.pipeline().names());
//
ctx.write(msg);
}
});
[main] --- : channel: AbstractBootstrap$PendingRegistrationPromise@1de76cc7(incomplete)
[main] --- : 服务端启动成功 ~~~~ listening port : 8080
[nioEventLoopGroup-3-1] --- handler1 读取到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[nioEventLoopGroup-3-1] --- handler2 读取到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
[nioEventLoopGroup-3-1] --- handler3 读取到消息: PooledUnsafeDirectByteBuf(ridx: 0, widx: 6, cap: 2048)
1.9 Pipeline操作API总结
操作 | 方法 | 说明 |
---|---|---|
添加 | addFirst() , addLast() , addBefore() , addAfter() |
动态添加 Handler |
删除 | remove(handler) |
移除指定 Handler |
替换 | replace(oldHandler, newName, newHandler) |
替换 Handler |
查找 | get(name) |
获取 Handler |
遍历 | names() |
获取所有 Handler 名称 |
1.10 最佳实践与常见陷阱
1.10.1 ✅ 推荐实践
实践 | 说明 |
---|---|
合理组织 Handler 顺序 | 解码 → 认证 → 业务 → 编码 |
无状态 Handler 标记 @Sharable |
提高性能 |
使用 SimpleChannelInboundHandler |
自动释放资源 |
在 exceptionCaught 中关闭连接 |
防止资源泄漏 |
避免阻塞 Handler | 如 Thread.sleep() |
1.10.2 ⚠️ 常见错误
// ❌ 错误:忘记 fireChannelRead,事件中断
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// 处理后忘记继续传播
// 后续 Handler 将收不到事件
}
// ✅ 正确:调用 fire 或 write
ctx.fireChannelRead(msg); // 入站
ctx.write(msg); // 出站
1.11 Pipeline的优缺点总结
1.11.1 ✅ 优点
优点 | 说明 |
---|---|
高度解耦 | 业务与网络层分离 |
可扩展性强 | 灵活组合、动态修改 |
支持编解码 | 内置丰富编解码器 |
线程安全 | 事件串行执行,无锁 |
内存高效 | 零拷贝 + 自动释放 |
1.11.2 ❌ 缺点
缺点 | 说明 |
---|---|
学习成本高 | 需理解事件传播方向 |
调试复杂 | 事件在多个节点间流动 |
内存泄漏风险 | 忘记释放 ByteBuf |
过度设计风险 | 简单场景可能过于复杂 |
1.12 总结: Pipeline的核心价值
维度 | 说明 |
---|---|
核心角色 | Netty 的“事件调度中心” |
设计模式 | 责任链 + 事件驱动 |
核心能力 | 组织处理器、传播事件、管理资源 |
适用场景 | 所有网络通信:HTTP、WebSocket、RPC、MQTT |
Netty 地位 | 与 EventLoop 、Future 并列为三大基石 |
1.13 一句话总结
ChannelPipeline
是 Netty 的“神经中枢”- 它通过双向链表组织
Handler
,驱动事件在入站与出站路径上高效流动 - 实现了高性能、可扩展、易维护的异步网络处理架构,是构建现代高并发网络应用的核心引擎。
- 它通过双向链表组织
更多推荐
所有评论(0)