# 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 时执行(连接刚建立第一步
作用:通道注册成功通知

@Override
public void channelRegistered(ChannelHandlerContext ctx) {
System.out.println("channelRegistered 注册1");
super.channelRegistered(ctx);
}

Channel 与 NIO 线程(EventLoop)完成绑定,相当于“拿到工作证”。


2. channelActive(ChannelHandlerContext ctx)

执行时机:通道注册完成、TCP 连接真正建立成功
作用:连接激活,客户端已成功连上服务器

@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("channelActive 通道存活");
super.channelActive(ctx);
}

实战意义: 可以在这里做:连接统计、初始化用户信息、发送欢迎消息。


3. channelRead(ChannelHandlerContext ctx, Object msg)

执行时机:收到客户端任意数据时触发
作用:读取原始消息(Netty 底层调用)

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("channelRead 读开始");
super.channelRead(ctx, msg);
}

这是入站处理的入口,super.channelRead 会自动调用 acceptInboundMessage 做类型判断。


4. acceptInboundMessage(Object msg)

执行时机:channelRead 之后,判断是否处理当前消息
作用:消息类型匹配检查

@Override
public boolean acceptInboundMessage(Object msg) {
return super.acceptInboundMessage(msg);
}

原理: 继承的是 SimpleChannelInboundHandler<String>,所以它会判断: msg instanceof String 匹配成功 → 进入 channelRead0 匹配失败 → 跳过不处理


5. channelRead0(ChannelHandlerContext ctx, String msg)

【核心业务方法】 执行时机:类型匹配成功后执行
作用:处理真正的业务逻辑(你 90% 代码写在这里)

@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
//处理读消息
}

关键点

  • 自动释放消息(不需要手动 ReferenceCountUtil.release)
  • 泛型指定什么类型,这里就收到什么类型
  • 最推荐写业务逻辑的地方

6. channelReadComplete(ChannelHandlerContext ctx)

执行时机:一批数据读取完成后触发
作用:读取完毕通知,可在这里批量 flush

@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
System.out.println("channelReadComplete 读完成");
super.channelReadComplete(ctx);
}

7. channelInactive(ChannelHandlerContext ctx)

执行时机:TCP 连接断开(客户端断开/网络异常)
作用:连接失效
顺序:先 inactive,再 unregistered

@Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("channelInactive 通道不存活");
super.channelInactive(ctx);
}

8. channelUnregistered(ChannelHandlerContext ctx)

执行时机:通道从 EventLoop 注销
作用:连接彻底关闭,做资源清理

@Override
public void channelUnregistered(ChannelHandlerContext ctx) {
record.get(ctx.channel()).toString(); // 清理聊天记录
super.channelUnregistered(ctx);
}

实战:在这里清理连接缓存、会话、统计离线。


9. exceptionCaught(ChannelHandlerContext ctx, Throwable cause)

执行时机:发生异常(解码失败、连接异常、业务报错)
作用:全局异常捕获

@Override
public 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 注册1
channelActive 通道存活
channelRead 读开始
acceptInboundMessage 是否处理这个消息
channelRead0 处理读
channelRead0 你好1776571591235
channelReadComplete 读完成
channelReadComplete 读完成
channelInactive 通道不存活
channelUnregistered 通道关闭
My avatar

感谢阅读我的博客文章!欢迎查看我的其他帖子


更多博客