Netty源码:ChannelHandlerContext

ChannelHandlerContext

Posted by ZhaoLe on February 7, 2019

对Netty中的ChannelHandlerContext的文档大概翻译一下.

概述

ChannelHandlerContext 可以让一个ChannelHandler与它的ChannelPipeline和其他handler交互。此外一个处理器可以通知ChannelPipeline中下一个ChannelHandler并且可以动态修改它所属的ChannelPipeline对象

通知

可以通过调用里面的一些方法通知同一个ChannelPipeline中最近的handler

修改pipeline

可以调用pipeline()方法来获取这个handler所属的ChannelPipeline对象,应用可以在pipeline运行中动态的插入删除替换handler

获取供后续使用

可以获取一个ChannelHandlerContext供后续使用,例如在handler方法之外,甚至不同的线程中触发一个事件

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyHandler extends {@link ChannelDuplexHandler} {

private  ChannelHandlerContext ctx;

public void beforeAdd({@link ChannelHandlerContext} ctx) {
  this.ctx = ctx;
}

public void login(String username, password) {
    ctx.write(new LoginMessage(username, password));
}
...
}

存储状态信息

attr(AttributeKey允许你存储和访问跟handler和它的context有关的状态的信息

一个handler可以拥有多个context

一个ChannelHandler可以多次添加到ChannelPipeline中,这就意味这个一个ChanndlHandler实例可以拥有多个ChannelHandlerContext ,因此一个单例可以在不同的ChannelHaandlerContext被调用,如果它被添加到 ChannelPipeline中超过一次。 举个例子。如下的handler会拥有多个独立的AttributeKey,取决于添加到pipeline中次数,不论它是被添加到相同pipeline多次,还是不同pipeline中多次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 public class FactorialHandler extends  ChannelInboundHandlerAdapter {
 
    private final AttributeKey<Integer>; counter = AttributeKey.valueOf("counter");
 
    // This handler will receive a sequence of increasing integers starting
    // from 1.
    @Override 
    public void channelRead (ChannelHandlerContext  ctx, Object msg) {
      Integer a = ctx.attr(counter).get();
 
      if (a == null) {
        a = 1;
      }
 
      attr.set(a * (Integer) msg);
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
/*
*不同的context对象赋值"f1", "f2", "f3", and "f4",尽管它们是同一个handler实例
* 因为FactorialHandler在context对象(使用AttributeKey)中存储了自己的状态。
* 当两个pipeline处于活动状态下,它会被计算四次
*/
ChannelPipeline  p1 =   Channels.pipeline();
p1.addLast("f1", fh);
p1.addLast("f2", fh);

ChannelPipeline  p2 =  Channels.pipeline();
p2.addLast("f3", fh);
p2.addLast("f4", fh);

下面是摘自《Netty实战》

关系图 IMAGE

ChannelHandlerContext 代表了 ChannelHandler 和 ChannelPipeline 之间的关 联,每当有 ChannelHandler 添加到 ChannelPipeline 中时,都会创建 ChannelHandlerContext

事件的流动 IMAGE

ChannelHandlerContext 有很多的方法,其中一些方法也存在于 Channel 和 ChannelPipeline 本身上,但是有一点重要的不同。如果调用Channel或者ChannelPipeline 上的这 些方法,它们将沿着整个 ChannelPipeline 进行传播。而调用位于 ChannelHandlerContext 上的相同方法,则将从当前所关联的 ChannelHandler 开始,并且只会传播给位于该 ChannelPipeline 中的下一个能够处理该事件的 ChannelHandler。