
2-Netty核心组件详解核心概念组件关系全景图EventLoopGroup └── EventLoop (1个线程 1个Selector) └── Channel (网络连接) └── ChannelPipeline (处理链) ├── HeadContext (出站起点) ├── Handler1 ├── Handler2 └── TailContext (入站起点) ChannelHandlerContext ├── 绑定 Handler 与 Pipeline ├── 可以向前/向后传递事件 └── 可以获取 Channel、EventLoop 等引用EventLoop 核心要点与实际应用特性说明实战示例线程绑定一个 EventLoop 对应一个线程线程资源隔离避免锁竞争。EventLoop对象可通过eventLoop.inEventLoop()检查当前调用线程是否为其所属线程。Channel 绑定一个 Channel 只属于一个 EventLoop生命周期内所有 IO 事件读/写/连接/关闭都由同一线程处理。最佳实践创建Channel时即指定其归属的EventLoop。多 Channel 管理一个 EventLoop 可以管理多个 Channel通过一个Selector同时监听多个Channel的 IO 就绪事件实现单线程高并发。代码示例ServerBootstrap中通常配置bossGroup(1)和workerGroup(n)。串行执行所有 IO 操作在 EventLoop 线程中串行执行天然保证了ChannelPipeline中Handler执行的线程安全性无需额外加锁。风险任一Handler阻塞将导致该EventLoop下所有Channel卡死。避免阻塞Handler 中不要执行耗时操作错误示例在channelRead中直接进行数据库查询。正确做法将耗时任务提交至业务线程池通过Promise异步返回结果。ctx.channel().eventLoop().execute(task)或ctx.executor().submit(task)。ByteBuf 内部结构与内存管理详解关键操作与代码示例写入与读取ByteBufbufferUnpooled.buffer(1024);buffer.writeInt(100);// writerIndex 移动 4 字节intvaluebuffer.readInt();// readerIndex 移动 4 字节System.out.println(剩余可读字节buffer.readableBytes());内存压缩与切片// discardReadBytes() 会移动数据成本较高仅在必要时调用if(buffer.readerIndex()buffer.capacity()*0.5){buffer.discardReadBytes();}// slice() 和 duplicate() 创建零拷贝视图共享底层数据ByteBufslicedbuffer.slice(buffer.readerIndex(),10);引用计数释放// 继承自 SimpleChannelInboundHandler自动释放publicclassMyHandlerextendsSimpleChannelInboundHandlerByteBuf{OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,ByteBufmsg){// 无需手动释放}}// 使用 ChannelInboundHandlerAdapter必须手动释放OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg){ByteBufbuf(ByteBuf)msg;try{// ... 处理 buf}finally{ReferenceCountUtil.release(buf);// 或 buf.release();}}堆内存 vs 直接内存性能对比对比项HeapByteBufDirectByteBuf生产建议分配速度快在 JVM 堆内分配慢调用系统 API 在堆外分配频繁创建/销毁的小对象可用堆内存。GC 影响受 GC 管理Full GC 可能停顿不受 GC 管理但需手动管理释放生命周期长的缓冲区如文件传输用直接内存避免 GC 压力。IO 效率网络传输前需拷贝到直接内存一次拷贝零拷贝可直接通过 DMA 发送高性能服务器默认使用直接内存。可通过-Dio.netty.noPreferDirectfalse配置。内存占用占用 JVM 堆空间占用系统内存不反映在 JVM 堆指标中监控需同时关注 JVM 堆和系统内存。ChannelFuture 异步编程与异常处理1. 异步回调完整示例ChannelFuturefuturebootstrap.connect(127.0.0.1,8080);// 推荐添加监听器非阻塞future.addListener((ChannelFutureListener)f-{if(f.isSuccess()){Channelchannelf.channel();channel.writeAndFlush(Unpooled.copiedBuffer(Hello,CharsetUtil.UTF_8));System.out.println(连接成功Channel: channel.id());}else{Throwablecausef.cause();System.err.println(连接失败原因: cause.getMessage());// 重连逻辑或资源清理f.channel().eventLoop().schedule(()-reconnect(),5,TimeUnit.SECONDS);}});2. 异常处理策略连接异常监听 CLOSE_ON_FAILURE自动关闭 Channel 并记录日志。写操作异常为writeAndFlush返回的ChannelFuture添加监听器处理IOException。超时控制结合EventLoop的schedule方法实现超时回调。ChannelFuturewriteFuturechannel.writeAndFlush(msg);ChannelFuturetimeoutFuturechannel.eventLoop().schedule(()-{if(!writeFuture.isDone()){writeFuture.cancel(true);System.err.println(写操作超时);}},10,TimeUnit.SECONDS);writeFuture.addListener(f-timeoutFuture.cancel(false));// 成功则取消超时任务3. 内置监听器快捷使用ChannelFuturecloseFuturechannel.closeFuture();closeFuture.addListener(ChannelFutureListener.CLOSE);// 关闭后自动清理closeFuture.addListener(f-log.info(Channel closed: {},f.channel().id()));ChannelPipeline 实战与自定义 Handler1. Pipeline 执行流程示例假设配置了三个HandlerLogHandler-DecodeHandler-BusinessHandler。// 入站事件如收到数据流向Head - LogHandler - DecodeHandler - BusinessHandler - Tail// 出站事件如发送数据流向Tail - BusinessHandler - DecodeHandler - LogHandler - Head// 自定义 Handler 示例一个简单的字符串解码器publicclassStringDecoderextendsByteToMessageDecoder{Overrideprotectedvoiddecode(ChannelHandlerContextctx,ByteBufin,ListObjectout){if(in.readableBytes()4)return;// 长度字段不足等待in.markReaderIndex();intlengthin.readInt();if(in.readableBytes()length){in.resetReaderIndex();// 数据不完整重置读指针return;}byte[]bytesnewbyte[length];in.readBytes(bytes);out.add(newString(bytes,StandardCharsets.UTF_8));// 向下游传递解码后的对象}}2. Handler 生命周期与线程安全handlerAdded/handlerRemoved在Handler被加入/移除Pipeline时调用可用于初始化/清理资源。channelActive/channelInactive在Channel激活/失效时调用。重要Handler实例通常被多个Channel共享除非标注Sharable因此成员变量需考虑线程安全或使用AttributeKey。publicclassMyBusinessHandlerextendsChannelInboundHandlerAdapter{privatestaticfinalAttributeKeySessionSESSION_KEYAttributeKey.newInstance(session);OverridepublicvoidchannelActive(ChannelHandlerContextctx){// 为每个 Channel 创建独立的会话对象ctx.channel().attr(SESSION_KEY).set(newSession());}OverridepublicvoidchannelRead(ChannelHandlerContextctx,Objectmsg){Sessionsessionctx.channel().attr(SESSION_KEY).get();// 使用 session 处理业务线程安全}}3. 生产环境最佳实践Pipeline 配置将编解码、日志、流量统计等通用Handler放在前面业务Handler放在后面。资源释放继承SimpleChannelInboundHandler自动释放ByteBuf或在finally块中手动释放。异常传播未处理的异常会沿Pipeline向后传播至TailContext并记录日志也可自定义ExceptionHandler集中处理。性能监控添加IdleStateHandler检测连接空闲添加自定义Handler统计请求耗时和 QPS。注意事项ByteBuf 未释放使用ChannelInboundHandlerAdapter时必须手动调用release()阻塞 EventLoop在 Handler 中执行数据库查询、HTTP 调用等耗时操作跨线程操作不能在非 EventLoop 线程中直接操作 Channel需要使用eventLoop.execute()