类定义:
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
implements ChannelHandlerContext, ResourceLeakHint {}
类属性:
next && prev
每个AbstractChannelHandlerContext都保存有两个属性, next和prev, 明显是做链表.
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
在DefaultChannelPipeline中, 则保存了名为head和tail的两个引用:
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
这样在DefaultChannelPipeline中就实现了一个从head一路next/next到tail, 再从tail一路prev/prev到head的一个双向链表.
inbound && outbound
这两个属性用来表明当前handler是inbound还是outbound, 通常和ChannelInboundHandler/ChannelOutboundHandler联系起来,.
比如HeadContext实现了ChannelOutboundHandler, 而TailContext实现了ChannelInboundHandler, 他们在调用super构造函数时就写死了inbound和outbound属性:
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
private final Unsafe unsafe;
HeadContext(DefaultChannelPipeline pipeline) {
super(pipeline, null, HEAD_NAME, false, true);
unsafe = pipeline.channel().unsafe();
setAddComplete();
}
}
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
TailContext(DefaultChannelPipeline pipeline) {
super(pipeline, null, TAIL_NAME, true, false);
setAddComplete();
}
}
netty设计上是使用两个boolean来记录inbound/outbound,
在DefaultChannelHandlerContext的实现中, 通过检查传入的handler来判断inbound/outbound, 判断的方法非常直接, instanceof ChannelInboundHandler/ChannelOutboundHandler:
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;
}
@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;
}
类方法:
setRemoved()
这是一个非常特别的属性, 只用于非常极端的情况, getter/setter方法如下:
final void setRemoved() {
handlerState = REMOVE_COMPLETE;
}
@Override
public boolean isRemoved() {
return handlerState == REMOVE_COMPLETE;
}
其中setRemoved()还不是public的, 调用的地方只有一处, 在类DefaultChannelPipeline:
private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
// Notify the complete removal.
try {
try {
// 从context 删除之后不在调用, handlerRemoved()自带方法
ctx.handler().handlerRemoved(ctx);
} finally {
ctx.setRemoved();
}
} catch (Throwable t) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
}
}
AttributeKey 相关方法
ChannelHandlerContext申明继承AttributeMap, AbstractChannelHandlerContext中有实现AttributeMap要求的两个方法:
@Override
public <T> Attribute<T> attr(AttributeKey<T> key) {
return channel().attr(key);
}
@Override
public <T> boolean hasAttr(AttributeKey<T> key) {
return channel().hasAttr(key);
}
最终还是delegate给channel的对应方法了.
Inbound 的IO 事件方法
这些方法最终都是delegate给invoker的对应方法, 以fireChannelRegistered()为例:
@Override
public ChannelHandlerContext fireChannelRegistered() {
// 找到下一个inbound 的 context,并调用invokeChannelRegistered() 方法
invokeChannelRegistered(findContextInbound());
return this;
}
static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
}
private void invokeChannelRegistered() {
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRegistered(this);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRegistered();
}
}
private AbstractChannelHandlerContext findContextInbound() {
// ctx 初始化为指向当前的context, 也就是this
AbstractChannelHandlerContext ctx = this;
do {
// 然后指向ctx 的next 指针,向后找
ctx = ctx.next;
} while (!ctx.inbound); // 检查是否是inbound,如果不是则继续next,直到找到下一个
return ctx;
}
这和javadoc中对这些方法的说明一致: “这些方法会导致当前Channel的ChannelPipeline中包含的下一个ChannelInboundHandler的相应的方法被调用”
类似的方法有一下:
ChannelHandlerContext fireChannelRegistered();
ChannelHandlerContext fireChannelUnregistered();
ChannelHandlerContext fireChannelActive();
ChannelHandlerContext fireChannelInactive();
ChannelHandlerContext fireExceptionCaught(Throwable cause); // 这个例外!
ChannelHandlerContext fireUserEventTriggered(Object event);
ChannelHandlerContext fireChannelRead(Object msg);
ChannelHandlerContext fireChannelReadComplete();
ChannelHandlerContext fireChannelWritabilityChanged();
但是fireExceptionCaught方法非常的特殊, 与众不同的是, 这个方法中的next是不区分inbound和outbound的, 直接取this.next:
@Override
public ChannelHandlerContext fireExceptionCaught(final Throwable cause) {
invokeExceptionCaught(next, cause);
return this;
}
static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) {
ObjectUtil.checkNotNull(cause, "cause");
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeExceptionCaught(cause);
} else {
try {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeExceptionCaught(cause);
}
});
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to submit an exceptionCaught() event.", t);
logger.warn("The exceptionCaught() event that was failed to submit was:", cause);
}
}
}
}
outbound 的 IO方法
首先, 下面这些方法在实现时都会转变为他们对应的带promise的版本:
ChannelFuture bind(SocketAddress localAddress);
ChannelFuture connect(SocketAddress remoteAddress);
ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress);
ChannelFuture disconnect();
ChannelFuture close();
ChannelFuture deregister();
例如bind()方法, 通过newPromise()方法创建一个promise之后, 就调用带promise的版本了:
@Override
public ChannelFuture bind(SocketAddress localAddress) {
return bind(localAddress, newPromise());
}
@Override
public ChannelPromise newPromise() {
return new DefaultChannelPromise(channel(), executor());
}
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
// 找到下一个 outbound 的context
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null);
}
return promise;
}
private AbstractChannelHandlerContext findContextOutbound() {
AbstractChannelHandlerContext ctx = this;
do {
// 向前找
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
注意:在前面咱们已经说过,inbound 入站流是自下而上方向依次处理,出站流是自上而下的方向处理,入站表示接受IO请求,例如read() 读取数据, 出战outbound 表示请求IO操作,例如写数据、关闭IO等,所以inbound 找下一个是next, outbound 是 prev。