10-ChannelHandlerContext

ChannelHandlerContext

一、ChannelHandlerContext

  • ChannelHandlerContext是ChannelPipeline内部的节点封装对象,它继承了AttributeMap用于存储信息,实现了ChannelInboundInvoker和ChannelOutboundInvoker可进行事件的传播。
  • 这里提一下,ChannelPipeline也继承了ChannelInboundInvoker和ChannelOutboundInvoker接口
public interface AttributeMap {
   
    <T> Attribute<T> attr(AttributeKey<T> key);

    <T> boolean hasAttr(AttributeKey<T> key);
}
  • 下面是ChannelHandlerContext额外定义的方法
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {

    /**
     * 下面几个是组件操作方法,channel,executor(EventExecutor),name,handler,pipeline和本身,比如获取channel等
     * Return the {@link Channel} which is bound to the {@link ChannelHandlerContext}.
     */
    Channel channel();

    /**
     * Returns the {@link EventExecutor} which is used to execute an arbitrary task.
     */
    EventExecutor executor();

    /**
     * The unique name of the {@link ChannelHandlerContext}.The name was used when then {@link ChannelHandler}
     * was added to the {@link ChannelPipeline}. This name can also be used to access the registered
     * {@link ChannelHandler} from the {@link ChannelPipeline}.
     */
    String name();

    /**
     * The {@link ChannelHandler} that is bound this {@link ChannelHandlerContext}.
     */
    ChannelHandler handler();

    /**
     * Return {@code true} if the {@link ChannelHandler} which belongs to this context was removed
     * from the {@link ChannelPipeline}. Note that this method is only meant to be called from with in the
     * {@link EventLoop}.
     */
    boolean isRemoved();

    /**
     * 下面方法实现传播,继承于ChannelInboundInvoker和ChannelOutboundInvoker接口
     */
    @Override
    ChannelHandlerContext fireChannelRegistered();

    @Override
    ChannelHandlerContext fireChannelUnregistered();

    @Override
    ChannelHandlerContext fireChannelActive();

    @Override
    ChannelHandlerContext fireChannelInactive();

    @Override
    ChannelHandlerContext fireExceptionCaught(Throwable cause);

    @Override
    ChannelHandlerContext fireUserEventTriggered(Object evt);

    @Override
    ChannelHandlerContext fireChannelRead(Object msg);

    @Override
    ChannelHandlerContext fireChannelReadComplete();

    @Override
    ChannelHandlerContext fireChannelWritabilityChanged();

    @Override
    ChannelHandlerContext read();

    @Override
    ChannelHandlerContext flush();

    /**
     * 返回ChannelPipeline
     * Return the assigned {@link ChannelPipeline}
     */
    ChannelPipeline pipeline();

    /**
     * 内存分配方法
     * Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
     */
    ByteBufAllocator alloc();
}
  • ChannelHandlerContext内部额外定义的方法不多,主要是获取其内部封装的属性,比如:ChannelPipeline、ChannelHandler、EventExecutor、Channel等。另外还包括alloc内存分配方法,除此之外就是继承自接口的方法了。

二、AbstractChannelHandlerContext

  • AbstractChannelHandlerContext是ChannelHandlerContext的一个抽象实现,下图是ChannelHandlerContext和它的子类继承关系:

在这里插入图片描述

2.1 主要属性

  • 先看看AbstractChannelHandlerContext的主要属性;
  • 小结一下内部的属性主要包括:ChannelHandlerContext的状态(4个状态)、链表前驱后继节点、ChannelHandler类型、ChannelPipeline对象、EventExecutor、事件任务等。
 /**
     * Neither {@link ChannelHandler#handlerAdded(ChannelHandlerContext)}
     * nor {@link ChannelHandler#handlerRemoved(ChannelHandlerContext)} was called.
     * 初始化状态, handlerAdded和handlerRemoved都还没有被调用的状态
     */
    private static final int INIT = 0; 
    /**
     * {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} is about to be called.
     * 准备添加的状态,handlerAdded即将被调用
     */
    private static final int ADD_PENDING = 1; 
    /**
     * {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} was called.
     * 已经添加的状态,handlerAdded已经被调用
     */
    private static final int ADD_COMPLETE = 2;
    /**
     * {@link ChannelHandler#handlerRemoved(ChannelHandlerContext)} was called.
     * 已经移除的状态,handlerRemoved已经被调用
     */
    private static final int REMOVE_COMPLETE = 3; 

    /**
     * {@link #handlerState} 状态的原子更新器,CAS机制更新状态变量
     */
    private static final AtomicIntegerFieldUpdater<AbstractChannelHandlerContext> HANDLER_STATE_UPDATER = AtomicIntegerFieldUpdater.newUpdater(AbstractChannelHandlerContext.class, "handlerState");

    /**
     * 链表下一个节点
     */
    volatile AbstractChannelHandlerContext next;
    
    /**
     * 链表上一个节点
     */
    volatile AbstractChannelHandlerContext prev;
    
    /**
     * 标识handler类型,是否为inbound或者是否为outbound
     */
    private final boolean inbound;
    private final boolean outbound;

    /**
     * ChannelHandlerContext节点所属的pipeline
     */
    private final DefaultChannelPipeline pipeline;
    
    /**
     * 名字
     */
    private final String name;
    
    /**
     * 是否使用有序的 EventExecutor ( {@link #executor} ),即 OrderedEventExecutor
     */
    private final boolean ordered;

    // Will be set to null if no child executor should be used, otherwise it will be set to the
    // child executor.
    /**
     * EventExecutor 对象,没有child executor时会被设为为null
     */
    final EventExecutor executor;
    
    /**
     * 成功的 Promise 对象
     */
    private ChannelFuture succeededFuture;

    // Lazily instantiated tasks used to trigger events to a handler with different executor.
    // There is no need to make this volatile as at worse it will just create a few more instances then needed.
    /**
     * 执行 Channel ReadComplete 事件的任务
     */
    private Runnable invokeChannelReadCompleteTask;
    /**
     * 执行 Channel Read 事件的任务
     */
    private Runnable invokeReadTask;
    /**
     * 执行 Channel WritableStateChanged 事件的任务
     */
    private Runnable invokeChannelWritableStateChangedTask;
    /**
     *执行 flush 事件的任务
     */
    private Runnable invokeFlushTask;
    /**
     * 处理器初始状态
     */
    private volatile int handlerState = INIT;

2.2 构造方法

  • AbstractChannelHandlerContext构造方法会初始化部分属性
    /**
     * EventExecutor 对象
     */
    final EventExecutor executor;
    /**
     * 标识handler类型,是否为inbound或者是否为outbound
     */
    private final boolean inbound;
    private final boolean outbound;

    /**
     * ChannelHandlerContext节点所属的pipeline
     */
    private final DefaultChannelPipeline pipeline;

    AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, boolean inbound, boolean outbound) {
        //构造方法初始化重要的参数
        this.name = ObjectUtil.checkNotNull(name, "name");
        this.pipeline = pipeline;
        this.executor = executor;
        this.inbound = inbound;
        this.outbound = outbound;
        // Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
        ordered = executor == null || executor instanceof OrderedEventExecutor;
    }

2.3 属性获取方法

  • ChannelHandlerContext内部封装了ChannelHandler,并且其持有ChannelPipeline对象,ChannelHandlerContext的很多属性获取方法实际上是通过Pipeline对象获取的,比如获取Channel、内存分配器、EventExecutor等。
    @Override
    public Channel channel() {
        return pipeline.channel();
    }

    @Override
    public ByteBufAllocator alloc() {
        return channel().config().getAllocator();
    }
    
    @Override
    public EventExecutor executor() {
        if (executor == null) {
            return channel().eventLoop();
        } else {
            return executor;
        }
    }

2.4 事件传播方法

2.4.1 fireChannelRegistered
  • 事件传播方法继承自ChannelInboundInvoker接口,(注意ChannelPipeline和ChannelHandlerContext都同时继承了ChannelInboundInvoker和ChannelOutboundInvoker接口)
  • fireChannelRegistered:触发ChannelPipeline中后面一个ChannelInboundHandler的channelRegistered方法被调用
   /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelRegistered方法被调用
     * */
    @Override
    public ChannelHandlerContext fireChannelRegistered() {
        //1.findContextInbound会向后获得第一个ChannelInboundHandler
        invokeChannelRegistered(findContextInbound());
        return this;
    }
    
        private AbstractChannelHandlerContext findContextInbound() {
        // 循环,向后获得一个ChannelInboundHandler节点
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound);
        return ctx;
    }
  • fireChannelRegistered首先会找到后面一个ChannelHandlerContext节点,然后调用invokeChannelRegistered方法,在invokeChannelRegistered方法里面会获取后面一个节点的ChannelHandlerContext,然后执行invokeChannelRegistered方法;
    /**
     * 触发next的channelRegistered方法被调用
     * */
    static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
        //1.获取ChannelHandlerContext的EventExecutor
        EventExecutor executor = next.executor();
        //2.如果EventExecutor线程在EventLoop线程中,就直接调用
        if (executor.inEventLoop()) {
            next.invokeChannelRegistered();
        } else {
            //3.反之则递交给executor执行
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelRegistered();
                }
            });
        }
    }
  • invokeChannelRegistered方法是ChannelHandlerContext的方法,逻辑如下,invokeChannelRegistered内部首先会判断状态,返回true就调用内部持有的 ChannelHandler对象的channelRegistered方法,到这里其实我们发现逻辑上很简单,首先通过双向链表找到下一个链表节点,找到之后调用节点内部封装的ChannelHandler的需要fire的方法即可。
    /**
     *  触发channelRegistered方法被调用
     * */
    private void invokeChannelRegistered() {
        if (invokeHandler()) {
            try {
                //1.触发channelRegistered方法被调用,handler属性就是内部包装的ChannelHandler对象
                ((ChannelInboundHandler) handler()).channelRegistered(this);
            } catch (Throwable t) {
                //2.通知 Inbound 事件的传播,发生异常
                notifyHandlerException(t); 
            }
        } else {
            fireChannelRegistered();
        }
    }
  • invokeHandler:这里稍微看了一下invokeHandler方法,看注释意思是当返回false的时候,就传播事件,此时不能调用ChannelHandler的方法,
/**
     * 尽最大努力检测handlerAdded方法是否已经被调用,没有调用就返回false,如果调用了就返回true
     * Makes best possible effort to detect if {@link ChannelHandler#handlerAdded(ChannelHandlerContext)} was called
     * yet. If not return {@code false} and if called or could not detect return {@code true}.
     *
     * 如果返回false,就不能调用ChannelHandler,而是传播事件,因为有可能DefaultChannelPipeline已经将一个handler放进了双向链表,
     * 但是尚未调用handlerAdded
     * 
     * If this method returns {@code false} we will not invoke the {@link ChannelHandler} but just forward the event.
     * This is needed as {@link DefaultChannelPipeline} may already put the {@link ChannelHandler} in the linked-list
     * but not called {@link ChannelHandler#handlerAdded(ChannelHandlerContext)}.
     */
    private boolean invokeHandler() {
        // 保存变量减少volatile读取 Store in local variable to reduce volatile reads.
        int handlerState = this.handlerState;
        return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);
    }
  • 上面的流程基本上分析了fireChannelRegistered的大致过程,实际上其他的fireXX方法也是类似的,基本思想就是找到下一个ChannelHandlerContext节点然后调用其内部的ChannelHandler对象对应的方法,其他类似方法就不一一分析了。
2.4.2 fireChannelRead
  • fireChannelRead方法是入站事件,对应于读取事件,我们在看看这个流程,大体上和前面的类似
/**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelRead方法被调用
     * */
    @Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {
        //触发ChannelPipeline中后面一个ChannelInboundHandler的channelRead方法被调用
        invokeChannelRead(findContextInbound(), msg);
        return this;
    }

    /**
     * 触发ChannelPipeline中后面一个ChannelInboundHandler的channelRead方法被调用
     * */
    static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
        //1.
        final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
        EventExecutor executor = next.executor();
        //2.下面的套路一样
        if (executor.inEventLoop()) {
            next.invokeChannelRead(m);
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelRead(m);
                }
            });
        }
    }
    
    /**
     * 调用下一个入站处理器的channelRead方法,将消息传递过去
     * */
    private void invokeChannelRead(Object msg) {
        if (invokeHandler()) {
            try {
                //1.调用内部的 ChannelHandler的channelRead方法
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
                //2.通知 Inbound 事件的传播,发生异常
                notifyHandlerException(t); 
            }
        } else {
            fireChannelRead(msg);
        }
    }

三、实现类

3.1 DefaultChannelHandlerContext

  • DefaultChannelHandlerContext是ChannelHandlerContext的默认实现类,不过主要功能都在AbstractChannelHandlerContext中已经实现好了,DefaultChannelHandlerContext非常简单。
final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {

    /**
     * 内部持有的ChannelHandler对象
     */
    private final ChannelHandler handler;

    /**
     * 构造方法
     */
    DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {

        super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
        if (handler == null) {
            throw new NullPointerException("handler");
        }
        this.handler = handler;
    }

    /**
     * 返回内部持有的ChannelHandler对象,AbstractChannelHandlerContext中很多地方调用该方法
     */
    @Override
    public ChannelHandler handler() {
        return handler;
    }

    /**
     * 判断是入站处理器还是出站处理器
     */
    private static boolean isInbound(ChannelHandler handler) {
        return handler instanceof ChannelInboundHandler;
    }

    private static boolean isOutbound(ChannelHandler handler) {
        return handler instanceof ChannelOutboundHandler;
    }
}

3.2 HeadContext和TailContext

3.2.1 HeadContext
  • HeadContext是ChannelPipeline中的头节点,是一个比较特殊的节点,它一方面是ChannelHandlerContext的实现类因此是一个ChannelPipeline内部链表节点,另一方面它实现了入站出站接口ChannelOutboundHandler和ChannelInboundHandler,因此是一个双向处理器,通过内部持有的unsafe对象来做具体的读、写、连接、绑定端口等IO事件。

  • HeadContext即是入站处理器又是出站处理器,里面有很多方法,有些是空实现,功能上看HeadContext会将事件传播到下一个入站处理器。

3.2.2 TailContext
  • TailContext是ChannelPipeline中的尾节点,也是一个比较特殊的节点,它一方面是ChannelHandlerContext的实现类因此是一个ChannelPipeline内部链表节点,另一方面它实现了ChannelInboundHandler,因此是一个入站事件处理器,可处理入站事件。不过TailContext继承自ChannelInboundHandler的很多入站方法都是空方法。

  • TailContext大部分情况下是什么都不做,有几个方法会将未处理的异常打印Warn日志

  • 更多关于HeadContext和TailContext的内容可以阅读参考文章[1]

四、小结

  • ChannelHandlerContext内部封装了ChannelHandler和ChannelPipeline,最核心的是便于事件在ChannelHandler之间传播,根据双向链表找到后续节点处理。

五、参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值