Netty从0到1系列之Netty Pipeline【上】


推荐阅读:

【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


一、Netty Pipeline:责任链模式的核心实现

1.1 Pipeline是什么?

Pipeline 是 Netty 框架中的核心组件,它采用责任链模式来组织和管理所有的 ChannelHandler。Pipeline 定义了数据在网络通道中的处理流程,负责将入站和出站事件传递给正确的处理器,并确保处理器的执行顺序。

在 Netty 的高性能网络编程模型中,ChannelPipeline 是事件流动的“高速公路”和处理器调度的“指挥中枢”。它与 ChannelHandler 紧密协作,构成了 Netty 责任链模式 + 事件驱动的核心架构。

Pipeline 的核心特性:

  • 责任链模式:多个 Handler 组成处理链,每个 Handler 专注特定功能
  • 双向处理:支持入站(Inbound)和出站(Outbound)处理流程
  • 动态管理:可以运行时添加、移除和替换 Handler
  • 线程安全:保证在多线程环境下的安全操作
  • 事件传播:负责事件在 Handler 之间的传递和控制

1.2 Pipeline的架构设计

为了更好地理解 Pipeline 的工作原理,我们先来看一下它的整体架构:

在这里插入图片描述

Pipeline全景图:
在这里插入图片描述

🌟 核心定位

  • ChannelPipeline 是一个双向链表构成的处理流水线
  • 它管理 ChannelHandler 的执行顺序,驱动 I/O 事件在处理器间流动

1.3 核心概念

1.3.1 ChannelPipeline 是什么?

ChannelPipeline 的实现是一个 ChannelHandlerContext(包装了 ChannelHandler) 组成的双向链表.

  • 默认在读的时候,会自动添加一个head、tailchannelHandler.
  • 每个 Channel 都有且仅有一个 Pipeline
  • 它在 Channel 创建时自动创建
  • 用于组织 ChannelHandler,形成处理链

关键特性

  • 线程安全:可在任意线程中添加/删除 Handler
  • 动态修改:支持运行时调整处理流程
  • 事件路由:决定事件如何在 Handler 间传播
// ChannelPipeline核心代码
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;
}

添加核心代码

private void addFirst0(AbstractChannelHandlerContext newCtx) {
    AbstractChannelHandlerContext nextCtx = head.next;
    newCtx.prev = head;
    newCtx.next = nextCtx;
    head.next = newCtx;
    nextCtx.prev = newCtx;
}

在这里插入图片描述

// 类继承关系
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {

}

在这里插入图片描述

@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
    invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
    return this;
}
  • 入站处理器中,ctx.fireChannelRead(msg)调用下一个入站处理器;

  • ctx.channel().write(msg);, 从链表尾部触发【后续出站处理执行】

  • ctx.write(msg, promise) 的调用也会 触发上一个出站处理器

    • 注意: 是ChannelHandler添加顺序的上一个处理器

[!note]

  • ctx.channel.write(msg) 和 ctx.write(msg, promise)
    • ctx.channel.write(msg)是从尾部开始查找【出站顺序】
    • ctx.write(msg, promise)是从当前处理器的上一个出站处理器

1.3.2 ChannelHandlerContext:Pipeline 的“工位”

  • 每个 HandlerPipeline 中都有一个对应的 Context
  • 它是 HandlerPipeline 交互的桥梁
方法说明
ctx.fireChannelRead(msg)下一个入站 Handler 传播
ctx.write(msg)前面的出站 Handler 传播
ctx.pipeline()获取所属的 Pipeline
ctx.channel()获取所属的 Channel

🌟 关键区别

  • ctx.write() vs channel.write()
    • ctx.write():从当前节点向前传播
    • channel.write():从Tail 节点开始向前传播(等价于 pipeline.write())

1.3.3 头尾节点(Head & Tail)

节点类型作用
HeadContextChannelOutboundHandler + ChannelInboundHandler- 入站:读取 Socket 数据
- 出站:执行底层 I/O 操作(如 write()
TailContextChannelInboundHandler- 处理未被消费的入站消息(自动释放)
- 记录未处理的异常
  • 入站: 读取Socket数据
    • 入站处理器通常是 ChannelInboundHandlerAdapter 的子类,主要用来读取客户端数据,写回结果
  • 出站: 执行底层I/O操作(如write)
    • 出站处理器通常是 ChannelOutboundHandlerAdapter 的子类,主要对写回结果进行加工

1.4 事件传播机制深度解析

1.4.1 ✅ 入站事件(Inbound):Head → Tail

网络层 HeadHandler Decoder BusinessHandler TailHandler read() fireChannelRead(data) fireChannelRead(decodedMsg) fireChannelRead(processedMsg) release(msg) // Tail 自动释放 网络层 HeadHandler Decoder BusinessHandler TailHandler

触发场景

  • 数据到达(channelRead)
  • 连接建立(channelActive)
  • 连接断开(channelInactive)

1.4.2 ✅ 出站事件(Outbound):Tail → Head

BusinessHandler Encoder HeadHandler 网络层 write(msg) write(encodedBuf) unsafe.write(buf) // 底层 I/O BusinessHandler Encoder HeadHandler 网络层

触发场景

  • 发送数据(write())
  • 刷新缓冲(flush())
  • 绑定地址(bind())

1.5 Pipeline核心API用法

1.5.1 基础的 Pipeline 配置和使用

package cn.tcmeta.pipeline;

import io.netty.bootstrap.ServerBootstrap;
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.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author: laoren
 * @description: 基础的 Pipeline 配置和使用
 * @version: 1.0.0
 */
@Slf4j
public class BasicPipelineExample {
    public static final int PORT = 8080;
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup 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();

                            // 1. 添加编解码器
                            pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            pipeline.addLast("encoder", new StringDecoder(CharsetUtil.UTF_8));

                            // 2. 添加业务处理器
                            pipeline.addLast("firstHandler", new FirstHandler());
                            pipeline.addLast("secondHandler", new SecondHandler());
                            pipeline.addLast("thirdHandler", new ThirdHandler());

                            // 3. 打印pipeline结构
                            log.info("Pipeline structure: {}" , pipeline.names());

                            // 4. 动态添加处理器【演示使用】
                            ch.closeFuture().addListener(future -> {
                                log.info("连接关闭时Pipeline状态: {}", pipeline.names());
                            });
                        }
                    });

            ChannelFuture future = bootstrap.bind(PORT).sync();
            log.info("Server started at port {}", PORT);
            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    // 第一个处理器
    static class FirstHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("FirstHandler 处理: " + msg);
            ctx.fireChannelRead(msg); // 传递给下一个处理器
        }
    }

    // 第二个处理器
    static class SecondHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            String message = (String) msg;
            System.out.println("SecondHandler 处理: " + message);

            // 可以中断传递链
            if ("skip".equals(message)) {
                System.out.println("跳过后续处理");
                // 不调用 ctx.fireChannelRead(),中断传递
            } else {
                ctx.fireChannelRead(message.toUpperCase()); // 修改后传递
            }
        }
    }

    // 第三个处理器
    static class ThirdHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("ThirdHandler 收到: " + msg);
            ctx.writeAndFlush("处理完成: " + msg); // 发送响应
        }
    }
}

12:03:00 [INFO ] [nioEventLoopGroup-3-2] c.t.p.BasicPipelineExample - Pipeline structure: [BasicPipelineExample$1#0, decoder, encoder, firstHandler, secondHandler, thirdHandler, DefaultChannelPipeline$TailContext#0]
FirstHandler 处理: laoren

SecondHandler 处理: laoren

ThirdHandler 收到: LAOREN

12:03:08 [INFO ] [nioEventLoopGroup-3-2] c.t.p.BasicPipelineExample - 连接关闭时Pipeline状态: [decoder, encoder, firstHandler, secondHandler, thirdHandler, DefaultChannelPipeline$TailContext#0]

1.5.2 动态管理Pipeline

package cn.tcmeta.pipeline;

import io.netty.bootstrap.ServerBootstrap;
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.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author: laoren
 * @date: 2025/9/3 12:07
 * @description: 动态管理 Pipeline
 * @version: 1.0.0
 */
@Slf4j
public class DynamicPipelineManagement {
    private static class PipelineManagerHandler extends io.netty.channel.ChannelInboundHandlerAdapter {
        public static final String COMPRESSION_HANDLER = "compressionHandler";
        public static final String LOGGING_HANDLER = "loggingHandler";

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ChannelPipeline pipeline = ctx.pipeline();

            if (msg instanceof String message) {
                // 1. 动态添加处理器
                if (message.startsWith("ADD_COMPRESSION") &&
                        pipeline.get(COMPRESSION_HANDLER) == null) {
                    pipeline.addAfter(ctx.name(), COMPRESSION_HANDLER, new CompressionHandler());
                    ctx.writeAndFlush("COMPRESSION ADD SUCCESS! \n");
                    return;
                }

                // 2. 动态移除处理器
                if (message.startsWith("REMOVE_COMPRESSION")) {
                    if (pipeline.get(COMPRESSION_HANDLER) != null) {
                        pipeline.remove(COMPRESSION_HANDLER);
                        ctx.writeAndFlush("COMPRESSION Remove ok \n");
                    }
                    return;
                }

                // 3. 动态替换处理器
                if (message.startsWith("REPLACE_LOGGING")) {
                    if (pipeline.get(LOGGING_HANDLER) != null) {
                        pipeline.replace(LOGGING_HANDLER, "enhancedLogging",
                                new EnhancedLoggingHandler());
                        ctx.writeAndFlush("Logging Handler Replace!\n");
                    }
                    return;
                }

                // 4. 查看当前Pipeline结构
                if (message.startsWith("SHOW_PIPELINE")) {
                    ctx.writeAndFlush("Pipeline Struct: " + pipeline.names() + " \n");
                    return;
                }
            }
            ctx.fireChannelRead(msg);
        }
    }

    // 压缩处理器
    public static class CompressionHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("压缩处理: " + msg);
            ctx.fireChannelRead("COMPRESSED(" + msg + ")");
        }
    }

    // 基础日志处理器
    public static class LoggingHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("Logging: " + msg);
            ctx.fireChannelRead(msg);
        }
    }

    // 增强版日志处理器
    public static class EnhancedLoggingHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("增强日志[" + System.currentTimeMillis() + "]: " + msg);
            ctx.fireChannelRead(msg);
        }
    }

    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();
                            log.info("channel id is : {}", ch.id());
                            // 1. 添加编解码器
                            pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                            pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));

                            // 2. 添加业务处理器
                            pipeline.addLast("pipelineManagerHandler", new PipelineManagerHandler());

                            // 3. 添加日志处理器
                            // pipeline.addLast("logger", new io.netty.handler.logging.LoggingHandler());
                        }
                    });

            // 绑定端口号
            ChannelFuture future = bootstrap.bind(8080).sync();
            log.info("Server started at port 8080");

            // 等待关闭
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

客户端

在这里插入图片描述

服务器端

在这里插入图片描述

1.5.3 完整的 Pipeline 配置示例

package cn.tcmeta.pipeline;

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.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.CharsetUtil;

public class CompletePipelineExample {
    private static final int PORT = 8080;
    private static final ByteBuf DELIMITER = Unpooled.copiedBuffer("\n", CharsetUtil.UTF_8);

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
                     // 添加日志处理器(对ServerSocketChannel生效)
                     .handler(new LoggingHandler(LogLevel.INFO))
                     .childHandler(new ChannelInitializer<Channel>() {
                         @Override
                         protected void initChannel(Channel ch) throws Exception {
                             ChannelPipeline pipeline = ch.pipeline();
                             
                             // 1. 日志记录(第一个处理器)
                             pipeline.addLast("logging", new LoggingHandler(LogLevel.DEBUG));
                             
                             // 2. 解决粘包/拆包问题
                             // 方案1: 基于分隔符
                             pipeline.addLast("frameDecoder", 
                                 new DelimiterBasedFrameDecoder(1024, DELIMITER));
                             
                             // 方案2: 基于长度字段(二选一)
                             // pipeline.addLast("frameDecoder2",
                             //     new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
                             // pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                             
                             // 3. 编解码器
                             pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
                             pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));
                             
                             // 4. 业务处理器
                             pipeline.addLast("authHandler", new AuthenticationHandler());
                             pipeline.addLast("throttlingHandler", new ThrottlingHandler(1000)); // 1秒限流
                             pipeline.addLast("businessHandler", new BusinessLogicHandler());
                             pipeline.addLast("statsHandler", new StatisticsHandler());
                             
                             // 5. 异常处理(通常放在最后)
                             pipeline.addLast("exceptionHandler", new GlobalExceptionHandler());
                             
                             System.out.println("完整Pipeline配置: " + pipeline.names());
                         }
                     })
                     .option(ChannelOption.SO_BACKLOG, 128)
                     .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture future = bootstrap.bind(PORT).sync();
            System.out.println("服务器启动在端口: " + PORT);
            
            future.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

// 认证处理器
class AuthenticationHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof String message) {
            if (message.startsWith("AUTH:")) {
                // 处理认证逻辑
                if ("valid_token".equals(message.substring(5))) {
                    ctx.fireChannelRead("认证成功: " + message);
                } else {
                    ctx.writeAndFlush("认证失败\n");
                    return;
                }
            } else {
                ctx.fireChannelRead(msg);
            }
        }
    }
}

// 限流处理器
class ThrottlingHandler extends ChannelInboundHandlerAdapter {
    private final long minInterval;
    private long lastProcessTime;
    
    public ThrottlingHandler(long minIntervalMs) {
        this.minInterval = minIntervalMs;
        this.lastProcessTime = 0;
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastProcessTime >= minInterval) {
            lastProcessTime = currentTime;
            ctx.fireChannelRead(msg);
        } else {
            ctx.writeAndFlush("请求过于频繁,请稍后重试\n");
        }
    }
}

// 业务逻辑处理器
class BusinessLogicHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof String) {
            String response = processBusinessLogic((String) msg);
            ctx.writeAndFlush(response + "\n");
        }
    }
    
    private String processBusinessLogic(String message) {
        // 模拟业务处理
        return switch (message) {
            case "time" -> "当前时间: " + System.currentTimeMillis();
            case "stats" -> "服务器运行中";
            default -> "回声: " + message;
        };
    }
}

// 统计处理器
class StatisticsHandler extends ChannelInboundHandlerAdapter {
    private int messageCount = 0;
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        messageCount++;
        if (messageCount % 10 == 0) {
            System.out.println("已处理 " + messageCount + " 条消息");
        }
        ctx.fireChannelRead(msg);
    }
}

// 全局异常处理器
class GlobalExceptionHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.err.println("全局异常捕获: " + cause.getMessage());
        ctx.writeAndFlush("服务器内部错误\n");
        ctx.close();
    }
}

【注意事项】: 注意处理器添加的顺序.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值