重学Netty(六)——ChannelHandlerContext

所谓ChannelHandlerContext就是ChannelHandler上下文,因此它就可以看做是一个管理它所关联的ChannelHandler。那ChannelHandlerContext和ChannelHandler和ChannelPipeline和Channel之间的关系又是怎样的呢?

Channel

前面也说过Channel的获取和使用,在这说一说它的生命周期,说到Channel的生命周期那还得去ChannelInboundHandler中去看,因为一个Channel的入站,就足以看出它会经过哪些过程,可以自己实现一个SimpleChannelInboundHandler。
如下代码所示

package Netty.buffer_allocator;
/*
 * @Author  Wrial
 * @Date Created in 13:46 2020/4/17
 * @Description Channel的生命周期
 */

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class ChannelLifeHandler extends SimpleChannelInboundHandler {


    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Channel registered");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Channel unRegistered");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Channel active");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Channel inActive");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Read complete");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        System.out.println("用户事件触发");
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Channel writeabilityChanged");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
    }

    @Override
    public boolean isSharable() {
        System.out.println("共享?"+super.isSharable());
        return super.isSharable();
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Handler added");
        super.handlerAdded(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        System.out.println("Handler remove");
        super.handlerRemoved(ctx);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("read");
        System.out.println((String) msg);

    }
}

结果如下
在这里插入图片描述
可以看到Channel的生命周期和Handler的添加时机,它会先判断这个SimpleChannelInboundHandler是不是可以共享的,然后就说对处理器的添加,然后对请求的Channel进行注册,接受Channel后,Channel就说处于活跃状态,接下来就可以对Channel中的数据进行读,读完后,设置为inActive,取消对Channel的注册,然后移除Handler。

如果当这些状态改变了,这些事件就会被转发给ChannelPipeline中的ChannelHandler中去。
在这里插入图片描述
因此Channel主要的生命周期就如下图
在这里插入图片描述

ChannelHandler

在上面的程序中足以体现出ChannelHandler的生命周期了,对照上面的结果
在这里插入图片描述
ChannelHandler有两个重要的子类,就是ChannelInboundHandler和ChannelOutboundHandler。

ChannelInboundHandler

前面用到的SimpleChannelInboundHandler就是ChannelInboundHandler的子类,ChannelHandler是最顶级的父类。
在这里插入图片描述
在上面例子中也对其中方法进行了重写,下面看看这些方法的含义
在这里插入图片描述
在这里插入图片描述
如果实现ChannelInboundHandler的channelRead方法,用完需要进行显式的释放,可以通过ReferenceCountUtil.release(msg)方法进行释放。Netty将使用WARN级别的日志消息记录未释放的资源,使得可以非 常简单地在代码中发现违规的实例,每次需要进行释放很繁琐,因此Netty在它的基础上又进行了一层封装,那就是SimpleChannelInboundHandler,它可以自动释放资源,不需要手动释放操作。

ChannelOutboundHandler

出站操作相对于入站操作来说,出站操作就是请求方法,入站操作就是接收方
在这里插入图片描述
API如下
在这里插入图片描述
在这里插入图片描述

ChannelPipeline

ChannelPipeline就是拦截对应Channel的入站和出站事件的ChannelHandler的实例链。每新创建一个Channel都会被分配一个新的ChannelPipeline,这种关联是永久的,不能多也不能少,是Netty自动分配的不需要手动完成。

Pipeline可以看做是一个链表,因此它的执行总是从头到尾,因此在添加Handler的时候可以调整在链表中的位置
在这里插入图片描述
也可以访问ChannelPipeline中的ChannelHandler如get等操作
在这里插入图片描述

ChannelHandlerContext

ChannelHandlerContext里就包含着ChannelHandler中的上下文信息,每一个ChannelHandler被添加都ChannelPipeline中都会创建一个与其对应的ChannelHandlerContext。ChannelHandlerContext的功能就是用来管理它所关联的ChannelHandler和在同一个ChannelPipeline中ChannelHandler的交互。
如下图就是ChannelPipeline和Channel和ChannelHandler和ChannelHandlerContext之间的关系在这里插入图片描述

ChannelHandlerContext可以做到尽量减少它不感兴趣的ChannelHandler所带来的的开销,比如某个逻辑只需要某几个处理器,因此可以不用从头开始处理,直接从需要的第一个的ChannelHandler的地方进行处理。
在这里插入图片描述
如下图,可以看到绕过了前面很多的ChannelHandler减少了开销
在这里插入图片描述

因为一个ChannelHandler可以同时属于多个ChannelPipeline,因此它也是可以有多个ChannelHandlerContext,这种用法的ChannelHandler就可以使用@Sharable注解,因此在使用Sharable注解的时候要确定自己的ChannelHandler是线程安全的。

  • 13
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值