文章目录
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之间传播,根据双向链表找到后续节点处理。