netty handler 生命周期

Netty 中的 Handler 具有严格的生命周期管理,确保了在不同的阶段能够对数据流进行处理。了解 Handler 的生命周期有助于更好地管理资源、优化性能,以及正确地处理连接和数据。以下是 Netty 中 Handler 的主要生命周期回调方法:

1. Handler 的生命周期回调方法

  • handlerAdded(ChannelHandlerContext ctx)

    • 时机: 当一个 Handler 被添加到 ChannelPipeline 中时调用。
    • 用途: 在此方法中,可以进行一些初始化工作,比如分配资源、初始化状态等。
  • handlerRemoved(ChannelHandlerContext ctx)

    • 时机: 当一个 HandlerChannelPipeline 中移除时调用。
    • 用途: 在此方法中,可以释放资源、清理状态等。
  • 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 生命周期中的主要事件流

  1. Handler 添加到 Pipeline

    • handlerAdded() 被调用。
  2. Channel 注册到 EventLoop

    • channelRegistered() 被调用。
  3. Channel 激活

    • channelActive() 被调用,表示连接已建立。
  4. 处理 I/O 操作

    • channelRead() 处理读取的数据。
    • channelReadComplete() 表示读取操作完成。
  5. Channel 失活

    • channelInactive() 被调用,表示连接已关闭。
  6. Channel 从 EventLoop 注销

    • channelUnregistered() 被调用。
  7. 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();
    }
}

发表评论