共计 6508 个字符,预计需要花费 17 分钟才能阅读完成。
简介
咱们晓得 ChannelHandler 有两个十分重要的子接口,别离是 ChannelOutboundHandler 和 ChannelInboundHandler, 基本上这两个 handler 接口定义了所有 channel inbound 和 outbound 的解决逻辑。
不论是 ChannelHandler 还是 ChannelOutboundHandler 和 ChannelInboundHandler,简直他们中所有的办法都带有一个 ChannelHandlerContext 参数,那么这个 ChannelHandlerContext 到底是做什么用的呢?它和 handler、channel 有什么关系呢?
ChannelHandlerContext 和它的利用
相熟 netty 的敌人应该都接触过 ChannelHandlerContext,如果没有的话,这里有一个简略的 handler 的例子:
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {log.info("accepted channel: {}", ctx.channel());
log.info("accepted channel parent: {}", ctx.channel().parent());
// channel 沉闷
ctx.write("Channel Active 状态!\r\n");
ctx.flush();}
}
这里的 handler 继承了 SimpleChannelInboundHandler,只须要实现对应的办法即可。这里实现的是 channelActive 办法,在 channelActive 办法中,传入了一个 ChannelHandlerContext 参数,咱们能够通过应用 ChannelHandlerContext 来调用它的一些办法。
先来看一下 ChannelHandlerContext 的定义:
public interface ChannelHandlerContext extends AttributeMap, ChannelInboundInvoker, ChannelOutboundInvoker {
首先 ChannelHandlerContext 是一个 AttributeMap,能够用来存储多个数据。
而后 ChannelHandlerContext 继承了 ChannelInboundInvoker 和 ChannelOutboundInvoker, 能够触发 inbound 和 outbound 的一些办法。
除了继承来的一些办法之外,ChannelHandlerContext 还能够作为 channel,handler 和 pipline 的沟通桥梁,因为能够从 ChannelHandlerContext 中获取到对应的 channel,handler 和 pipline:
Channel channel();
ChannelHandler handler();
ChannelPipeline pipeline();
还要留神的是 ChannelHandlerContext 还返回一个 EventExecutor,用来执行特定的工作:
EventExecutor executor();
接下来,咱们具体看一下 ChannelHandlerContext 的实现。
AbstractChannelHandlerContext
AbstractChannelHandlerContext 是 ChannelHandlerContext 的一个十分重要的实现,尽管 AbstractChannelHandlerContext 是一个抽象类,然而它基本上实现了 ChannelHandlerContext 的所有性能。
首先看一下 AbstractChannelHandlerContext 的定义:
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint
AbstractChannelHandlerContext 是 ChannelHandlerContext 的一个具体实现。
通常来说一个 handler 对应一个 ChannelHandlerContext,然而在一个程序中可能会有多于一个 handler,那么如何在一个 handler 中获取其余的 handler 呢?
在 AbstractChannelHandlerContext 中有两个同样是 AbstractChannelHandlerContext 类型的 next 和 prev, 从而使得多个 AbstractChannelHandlerContext 能够构建一个双向链表。从而能够在一个 ChannelHandlerContext 中,获取其余的 ChannelHandlerContext,从而取得 handler 解决链。
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
AbstractChannelHandlerContext 中的 pipeline 和 executor 都是通过构造函数传入的:
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,
String name, Class<? extends ChannelHandler> handlerClass) {this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
this.executionMask = mask(handlerClass);
// Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
可能有敌人会有疑难了,ChannelHandlerContext 中的 channel 和 handler 是如何失去的呢?
对于 channel 来说,是通过 pipeline 来获取的:
public Channel channel() {return pipeline.channel();
}
对于 handler 来说,在 AbstractChannelHandlerContext 中并没有对其进行实现,须要在继承 AbstractChannelHandlerContext 的类中进行实现。
对于 EventExecutor 来说, 能够通过构造函数向 AbstractChannelHandlerContext 传入一个新的 EventExecutor,如果没有传入或者传入为空的话,则会应用 channel 中自带的 EventLoop:
public EventExecutor executor() {if (executor == null) {return channel().eventLoop();} else {return executor;}
}
因为 EventLoop 继承自 OrderedEventExecutor, 所以它也是一个 EventExecutor。
EventExecutor 次要用来异步提交工作来执行, 事实上 ChannelHandlerContext 中简直所有来自于 ChannelInboundInvoker 和 ChannelOutboundInvoker 的办法都是通过 EventExecutor 来执行的。
对于 ChannelInboundInvoker 来说,咱们以办法 fireChannelRegistered 为例:
public ChannelHandlerContext fireChannelRegistered() {invokeChannelRegistered(findContextInbound(MASK_CHANNEL_REGISTERED));
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();
}
});
}
}
fireChannelRegistered 调用了 invokeChannelRegistered 办法,invokeChannelRegistered 则调用 EventExecutor 的 execute 办法,将实在的调用逻辑封装在一个 runnable 类中执行。
留神,在调用 executor.execute 办法之前有一个 executor 是否在 eventLoop 中的判断。如果 executor 曾经在 eventLoop 中了,那么间接执行工作即可,不须要启用新的线程。
对于 ChannelOutboundInvoker 来说,咱们以 bind 办法为例,看一下 EventExecutor 是怎么应用的:
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {ObjectUtil.checkNotNull(localAddress, "localAddress");
if (isNotValidPromise(promise, false)) {
// cancelled
return promise;
}
final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
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, false);
}
return promise;
}
能够看到执行的逻辑和 invokeChannelRegistered 办法很相似,也是先判断 executor 在不在 eventLoop 中,如果在的话间接执行,如果不在则放在 executor 中执行。
下面的两个例子中都调用了 next 的相应办法,别离是 next.invokeChannelRegistered 和 next.invokeBind。
咱们晓得 ChannelHandlerContext 只是一个封装,它自身并没有太多的业务逻辑,所以 next 调用的相应办法,实际上是 Context 中封装的 ChannelInboundHandler 和 ChannelOutboundHandler 中的业务逻辑,如下所示:
private void invokeUserEventTriggered(Object event) {if (invokeHandler()) {
try {((ChannelInboundHandler) handler()).userEventTriggered(this, event);
} catch (Throwable t) {invokeExceptionCaught(t);
}
} else {fireUserEventTriggered(event);
}
}
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {if (invokeHandler()) {
try {((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
} catch (Throwable t) {notifyOutboundHandlerException(t, promise);
}
} else {bind(localAddress, promise);
}
}
所以,从 AbstractChannelHandlerContext 能够得悉,ChannelHandlerContext 接口中定义的办法都是调用的 handler 中具体的实现,Context 只是对 handler 的封装。
DefaultChannelHandlerContext
DefaultChannelHandlerContext 是 AbstractChannelHandlerContext 的一个具体实现。
咱们在解说 AbstractChannelHandlerContext 的时候提到过,AbstractChannelHandlerContext 中并没有定义具体的 handler 的实现,而这个实现是在 DefaultChannelHandlerContext 中进行的。
DefaultChannelHandlerContext 很简略,咱们看一下它的具体实现:
final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {
private final ChannelHandler handler;
DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {super(pipeline, executor, name, handler.getClass());
this.handler = handler;
}
@Override
public ChannelHandler handler() {return handler;}
}
DefaultChannelHandlerContext 中额定提供了一个 ChannelHandler 属性,用来存储传入的 ChannelHandler。
到此 DefaultChannelHandlerContext 能够传入 ChannelHandlerContext 中所有必须的 handler,channel,pipeline 和 EventExecutor。
总结
本节咱们介绍了 ChannelHandlerContext 和它的几个根本实现,理解到了 ChannelHandlerContext 是对 handler,channel 和 pipline 的封装,ChannelHandlerContext 中的业务逻辑,实际上是调用的是底层的 handler 的对应办法。这也是咱们在自定义 handler 中须要实现的办法。
本文已收录于 http://www.flydean.com/04-4-netty-channelhandlercontext/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!