# SimpleChannlInboundHandler生命周期方法详解
Table of Contents
Netty 核心 Handler SimpleChannelInboundHandler 全生命周期方法详解
在 Netty 中,SimpleChannelInboundHandler 是处理自定义业务逻辑最常用的处理器,它封装了消息自动释放、类型匹配等能力,让我们只需要关注业务处理。
它的本质是一个入站处理器(ChannelInboundHandlerAdapter),负责接收客户端数据、管理连接生命周期。
下面基于真实可运行的 Netty 服务端代码,逐行拆解每一个方法的执行时机、作用、底层逻辑。
一、先看执行顺序(最重要)
客户端连接 → 收发消息 → 断开连接,方法执行固定顺序:
channelRegistered → channelActive → channelRead → acceptInboundMessage → channelRead0 → channelReadComplete断开:channelInactive → channelUnregistered异常:exceptionCaught二、逐方法详细解析
1. channelRegistered(ChannelHandlerContext ctx)
执行时机:通道(Channel)被注册到 EventLoop 时执行(连接刚建立第一步
作用:通道注册成功通知
@Overridepublic void channelRegistered(ChannelHandlerContext ctx) { System.out.println("channelRegistered 注册1"); super.channelRegistered(ctx);}Channel 与 NIO 线程(EventLoop)完成绑定,相当于“拿到工作证”。
2. channelActive(ChannelHandlerContext ctx)
执行时机:通道注册完成、TCP 连接真正建立成功
作用:连接激活,客户端已成功连上服务器
@Overridepublic void channelActive(ChannelHandlerContext ctx) { System.out.println("channelActive 通道存活"); super.channelActive(ctx);}实战意义: 可以在这里做:连接统计、初始化用户信息、发送欢迎消息。
3. channelRead(ChannelHandlerContext ctx, Object msg)
执行时机:收到客户端任意数据时触发
作用:读取原始消息(Netty 底层调用)
@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) { System.out.println("channelRead 读开始"); super.channelRead(ctx, msg);}这是入站处理的入口,super.channelRead 会自动调用 acceptInboundMessage 做类型判断。
4. acceptInboundMessage(Object msg)
执行时机:channelRead 之后,判断是否处理当前消息
作用:消息类型匹配检查
@Overridepublic boolean acceptInboundMessage(Object msg) { return super.acceptInboundMessage(msg);}原理:
继承的是 SimpleChannelInboundHandler<String>,所以它会判断:
msg instanceof String
匹配成功 → 进入 channelRead0
匹配失败 → 跳过不处理
5. channelRead0(ChannelHandlerContext ctx, String msg)
【核心业务方法】
执行时机:类型匹配成功后执行
作用:处理真正的业务逻辑(你 90% 代码写在这里)
@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) { //处理读消息}关键点:
- 自动释放消息(不需要手动 ReferenceCountUtil.release)
- 泛型指定什么类型,这里就收到什么类型
- 最推荐写业务逻辑的地方
6. channelReadComplete(ChannelHandlerContext ctx)
执行时机:一批数据读取完成后触发
作用:读取完毕通知,可在这里批量 flush
@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) { System.out.println("channelReadComplete 读完成"); super.channelReadComplete(ctx);}7. channelInactive(ChannelHandlerContext ctx)
执行时机:TCP 连接断开(客户端断开/网络异常)
作用:连接失效
顺序:先 inactive,再 unregistered
@Overridepublic void channelInactive(ChannelHandlerContext ctx) { System.out.println("channelInactive 通道不存活"); super.channelInactive(ctx);}8. channelUnregistered(ChannelHandlerContext ctx)
执行时机:通道从 EventLoop 注销
作用:连接彻底关闭,做资源清理
@Overridepublic void channelUnregistered(ChannelHandlerContext ctx) { record.get(ctx.channel()).toString(); // 清理聊天记录 super.channelUnregistered(ctx);}实战:在这里清理连接缓存、会话、统计离线。
9. exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
执行时机:发生异常(解码失败、连接异常、业务报错)
作用:全局异常捕获
@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close();}必须重写,否则连接异常会导致通道泄露。
10. userEventTriggered / channelWritabilityChanged
不常用
- userEventTriggered:用户自定义事件触发
- channelWritabilityChanged:写缓冲区高低水位线变化(流量控制用)
三、完整生命周期流程图(记忆版)
客户端连接 ↓channelRegistered(注册) ↓channelActive(激活) ↓收到消息 ↓channelRead(读入口) ↓acceptInboundMessage(类型检查) ↓channelRead0(业务处理 ✔) ↓channelReadComplete(读完) ↓断开连接 ↓channelInactive(失活) ↓channelUnregistered(注销 → 清理资源)四、代码证明
new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println("channelRead0 处理读"); //读到了把聊天记录存起来 Channel channel = ctx.channel(); List<String> recordList = record.computeIfAbsent(channel, (c) -> new ArrayList<String>()); recordList.add(msg); }
@Override public boolean acceptInboundMessage(Object msg) throws Exception { System.out.println("acceptInboundMessage 是否处理这个消息"); return super.acceptInboundMessage(msg); }
@Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("channelRead 读开始"); super.channelRead(ctx, msg); }
@Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { System.out.println("channelRegistered 注册1"); super.channelRegistered(ctx); }
@Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { System.out.println("channelUnregistered 通道关闭"); System.out.println("通道关闭"+ record.get(ctx.channel()).toString());
super.channelUnregistered(ctx); }
@Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("channelActive 通道存活"); super.channelActive(ctx); }
@Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println("channelInactive 通道不存活"); super.channelInactive(ctx); }
@Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { System.out.println("channelReadComplete 读完成"); super.channelReadComplete(ctx); }
@Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { System.out.println("userEventTriggered"); super.userEventTriggered(ctx, evt); }
@Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { System.out.println("channelWritabilityChanged"); super.channelWritabilityChanged(ctx); }
@Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("exceptionCaught"); super.exceptionCaught(ctx, cause); }}结果分析
执行结果
channelRegistered 注册1channelActive 通道存活
channelRead 读开始acceptInboundMessage 是否处理这个消息channelRead0 处理读channelRead0 你好1776571591235channelReadComplete 读完成
channelReadComplete 读完成channelInactive 通道不存活channelUnregistered 通道关闭