Netty-ChannelInitializer-实现原理

本文探讨了Netty的ChannelInitializer的实现原理,它在连接生命周期中如何配置ChannelPipeline,以及如何利用处理程序的生命周期特性。同时,文章还分析了ChannelInitializer的源代码,包括关键方法的作用,如初始化Handler链、防止重复调用、资源管理以及与TCP连接建立、释放的关系。此外,还提及了解包粘包处理和高效的数据写入策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前的文章中解读了Netty对于一条连接的各个状态的生命周期进行了解读

1、ChannelInitializer的实现原理

  • 在定义handler的时候通过childHandler()方法设置了一个handle/也就是ChannelInitializer
  • ChannelInitializerinitChannel()方法中,通过获取channel对应的管道,在里面加入各种方法
//xxxxxxxxxxxxxx省略代码```
.childHandler(new ChannelInitializer<NioSocketChannel>() {
    protected void initChannel(NioSocketChannel ch) {
        ch.pipeline().addLast(new LifeCyCleTestHandler());
        ch.pipeline().addLast(new PacketDecoder());
        ch.pipeline().addLast(new LoginRequestHandler());
        ch.pipeline().addLast(new MessageRequestHandler());
        ch.pipeline().addLast(new PacketEncoder());
    }
});
  • ChannelInitializer其实就利用了Netty的处理程序生命周期中channelRegistered()handlerAdded()两个特性

2、ChannelInitializer类源代码

 protected abstract void initChannel(C ch) throws Exception;

    public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        // ...
        initChannel(ctx);
        // ...
    }

    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        // ...
        if (ctx.channel().isRegistered()) {
            initChannel(ctx);
        }
        // ...
    }

    private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
        if (initMap.putIfAbsent(ctx, Boolean.TRUE) == null) {
            initChannel((C) ctx.channel());
            // ...
            return true;
        }
        return false;
    }

1、ChannelInitializer定义了一个抽象的方法initChannel(),这个抽象方法由我们自行实现,我们在服务端启动的流程里面的实现逻辑就是往pipeline里面塞我们的handler链
2、handlerAdded()channelRegistered()方法,都会尝试去调用initChannel()方法,initChannel()使用putIfAbsent()来防止initChannel()被调用多次。在handlerAdded()方法被调用的时候,通道其实已经和某个线程绑定上了;
3、handlerAdded()handlerRemoved():通常可以用在一些资源的申请和释放
4、channelActive()channelInActive():TCP连接的建立与释放
5、channelRead():解包粘包原理,服务端根据自定义协议来进行拆包,其实就是在这个方法里面,每次读到一定的数据,都会累加到一个容器里面,然后判断是否能够拆出来一个完整的数据包,如果够的话就拆了之后,往下进行传递。
6、channelReadComplete():我们在每次向客户端写数据的时候,都通过writeAndFlush()的方法写并刷新到前面,其实这种方式不是特别高效,我们可以在之前调用writeAndFlush()的地方都调用write()方法,然后在这个方面里面调用ctx.channel().flush()方法,相当于一个批量刷新的机制,当然,如果你对性能要求没那么高,writeAndFlush()就可以。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值