Netty 中的 Handler 具有严格的生命周期管理,确保了在不同的阶段能够对数据流进行处理。了解 Handler 的生命周期有助于更好地管理资源、优化性能,以及正确地处理连接和数据。以下是 Netty 中 Handler 的主要生命周期回调方法:
1. Handler 的生命周期回调方法
-
handlerAdded(ChannelHandlerContext ctx)
- 时机: 当一个
Handler
被添加到ChannelPipeline
中时调用。 - 用途: 在此方法中,可以进行一些初始化工作,比如分配资源、初始化状态等。
- 时机: 当一个
-
handlerRemoved(ChannelHandlerContext ctx)
- 时机: 当一个
Handler
从ChannelPipeline
中移除时调用。 - 用途: 在此方法中,可以释放资源、清理状态等。
- 时机: 当一个
-
channelRegistered(ChannelHandlerContext ctx)
- 时机: 当 Channel 注册到一个 EventLoop 时调用。
- 用途: 这是处理程序可以开始处理 I/O 事件的地方,因为它表明该通道已经被注册。
-
channelUnregistered(ChannelHandlerContext ctx)
- 时机: 当 Channel 从 EventLoop 注销时调用。
- 用途: 在通道注销时进行清理工作。
-
channelActive(ChannelHandlerContext ctx)
- 时机: 当 Channel 变为活动状态(即连接建立)时调用。
- 用途: 表明 Channel 现在可以接收和发送数据。在这里通常进行连接成功后的初始化工作。
-
channelInactive(ChannelHandlerContext ctx)
- 时机: 当 Channel 变为不活动状态(即连接关闭)时调用。
- 用途: 用于清理连接相关的资源或状态。
-
channelRead(ChannelHandlerContext ctx, Object msg)
- 时机: 当有数据从远程端读取时调用。
- 用途: 这是数据处理的主要方法,接收并处理消息。
-
channelReadComplete(ChannelHandlerContext ctx)
- 时机: 当 Channel 上一次读取操作完成时调用。
- 用途: 可以用来触发批量处理或刷新操作。
-
exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
- 时机: 当处理过程中发生异常时调用。
- 用途: 在此方法中处理异常,比如关闭连接或记录日志。
2. Handler 生命周期中的主要事件流
-
Handler 添加到 Pipeline
handlerAdded()
被调用。
-
Channel 注册到 EventLoop
channelRegistered()
被调用。
-
Channel 激活
channelActive()
被调用,表示连接已建立。
-
处理 I/O 操作
channelRead()
处理读取的数据。channelReadComplete()
表示读取操作完成。
-
Channel 失活
channelInactive()
被调用,表示连接已关闭。
-
Channel 从 EventLoop 注销
channelUnregistered()
被调用。
-
Handler 从 Pipeline 中移除
handlerRemoved()
被调用。
在这个例子中,MyHandler
将在其生命周期中的不同阶段输出相关信息,这样你可以跟踪每个阶段的状态。
3. 总结
Netty 的 Handler 生命周期提供了一系列回调方法,这些方法在 Handler 被添加、移除、Channel 注册、注销、激活、失活,以及读写操作和异常处理中被调用。理解并正确使用这些回调方法,可以帮助你更好地管理 Netty 应用中的资源和逻辑。
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
public static int num = 0;
public NettyServerHandler() {
MyLog.info("构造函数进入 :" + (++num));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" handlerAdded in 1 ====");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" channelRegistered in 2 ====");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" channelActive in 3 ====");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" channelInactive out 1 ===");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" channelUnregistered out 2 === :" + (--num));
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" handlerRemoved out 3 ====");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("服务器读取线程 " + Thread.currentThread().getName() + " channel = " + ctx.channel());
System.out.println("server ctx = " + ctx);
Channel channel = ctx.channel();
ChannelPipeline pipeline = ctx.pipeline();
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端发送消息是: " + buf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址: " + channel.remoteAddress());
ReferenceCountUtil.release(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
MyLog.info(" channelReadComplete ");
ctx.writeAndFlush(Unpooled.copiedBuffer("hello, 客户端", CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
MyLog.info(" exceptionCaught 异常退出 :" + (--num));
cause.printStackTrace();
ctx.close();
}
}