netty在pipeline中寻找下一个处理节点的方法主要依靠位运算的方式,根据mask标记来进行查找
executionMask代表handler实现了哪几个处理方法
Handler加入pipeline最终会封装成DefaultChannelHandlerContext类
在DefaultChannelHandlerContext的构造函数中,对handler使用解析,查看他实现了哪几个方法
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,
String name, Class<? extends ChannelHandler> handlerClass) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
// 保存 入站处理、出站处理、异常处理的 标志位
// 替代了老版本里边 inbound ,outbound 标准位
// 细粒度的 处理操作 标志位
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;
}
这里需要解释ChannelHandlerMask类,它的主要作用是对出站处理,入站处理,异常处理的方法,使用位运算进行了映射
映射属性字段 | 对应的方法 |
---|---|
MASK_EXCEPTION_CAUGHT = 1 | exceptionCaught |
映射属性字段 | 对应的方法 |
---|---|
MASK_CHANNEL_REGISTERED = 1 << 1 | channelRegistered |
MASK_CHANNEL_UNREGISTERED = 1 << 2 | channelUnregistered |
MASK_CHANNEL_ACTIVE = 1 << 3 | channelActive |
MASK_CHANNEL_INACTIVE = 1 << 4 | channelInactive |
MASK_CHANNEL_READ = 1 << 5 | channelRead |
MASK_CHANNEL_READ_COMPLETE = 1 << 6 | channelReadComplete |
MASK_USER_EVENT_TRIGGERED = 1 << 7 | userEventTriggered |
MASK_CHANNEL_WRITABILITY_CHANGED = 1 << 8 | channelWritabilityChanged |
映射属性字段 | 对应的方法 |
---|---|
MASK_BIND = 1 << 9 | bind |
MASK_CONNECT = 1 << 10 | connect |
MASK_DISCONNECT = 1 << 11 | disconnect |
MASK_CLOSE = 1 << 12 | close |
MASK_DEREGISTER = 1 << 13 | deregister |
MASK_READ = 1 << 14 | read |
MASK_WRITE = 1 << 15 | write |
MASK_FLUSH = 1 << 16 | flush |
映射属性字段 | 对应的方法 |
---|---|
MASK_ONLY_INBOUND | 所有的入站处理操作进行或运算 |
MASK_ONLY_OUTBOUND | 所有的出站处理操作进行或运算 |
MASK_ALL_INBOUND | 所有入站处理操作+异常 |
MASK_ALL_OUTBOUND | 所有出站处理操作+异常 |
private static int mask0(Class<? extends ChannelHandler> handlerType) {
// mask 存储 处理器中 最终实现 出站处理、入站处理、异常的能力
int mask = MASK_EXCEPTION_CAUGHT;
try {
if (ChannelInboundHandler.class.isAssignableFrom(handlerType)) {
// 先 给到 所有的出站处理器的能力
mask |= MASK_ALL_INBOUND;
if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
// 去掉 CHANNEL_REGISTERED 入站处理
mask &= ~MASK_CHANNEL_REGISTERED;
}
if (isSkippable(handlerType, "channelUnregistered", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_UNREGISTERED;
}
if (isSkippable(handlerType, "channelActive", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_ACTIVE;
}
if (isSkippable(handlerType, "channelInactive", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_INACTIVE;
}
if (isSkippable(handlerType, "channelRead", ChannelHandlerContext.class, Object.class)) {
mask &= ~MASK_CHANNEL_READ;
}
if (isSkippable(handlerType, "channelReadComplete", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_READ_COMPLETE;
}
if (isSkippable(handlerType, "channelWritabilityChanged", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_WRITABILITY_CHANGED;
}
if (isSkippable(handlerType, "userEventTriggered", ChannelHandlerContext.class, Object.class)) {
mask &= ~MASK_USER_EVENT_TRIGGERED;
}
}
if (ChannelOutboundHandler.class.isAssignableFrom(handlerType)) {
mask |= MASK_ALL_OUTBOUND;
if (isSkippable(handlerType, "bind", ChannelHandlerContext.class,
SocketAddress.class, ChannelPromise.class)) {
mask &= ~MASK_BIND;
}
if (isSkippable(handlerType, "connect", ChannelHandlerContext.class, SocketAddress.class,
SocketAddress.class, ChannelPromise.class)) {
mask &= ~MASK_CONNECT;
}
if (isSkippable(handlerType, "disconnect", ChannelHandlerContext.class, ChannelPromise.class)) {
mask &= ~MASK_DISCONNECT;
}
if (isSkippable(handlerType, "close", ChannelHandlerContext.class, ChannelPromise.class)) {
mask &= ~MASK_CLOSE;
}
if (isSkippable(handlerType, "deregister", ChannelHandlerContext.class, ChannelPromise.class)) {
mask &= ~MASK_DEREGISTER;
}
if (isSkippable(handlerType, "read", ChannelHandlerContext.class)) {
mask &= ~MASK_READ;
}
if (isSkippable(handlerType, "write", ChannelHandlerContext.class,
Object.class, ChannelPromise.class)) {
mask &= ~MASK_WRITE;
}
if (isSkippable(handlerType, "flush", ChannelHandlerContext.class)) {
mask &= ~MASK_FLUSH;
}
}
if (isSkippable(handlerType, "exceptionCaught", ChannelHandlerContext.class, Throwable.class)) {
mask &= ~MASK_EXCEPTION_CAUGHT;
}
} catch (Exception e) {
// Should never reach here.
PlatformDependent.throwException(e);
}
return mask;
}
/**
* 判断当前handler是否存在以methodName命名的方法
* @param handlerType 当前handler的class
* @param methodName 要判断的方法名
* @param paramTypes 要判断的方法参数
* @return 存在@Skip为true,不存在@Skip为false
*/
private static boolean isSkippable(
final Class<?> handlerType, final String methodName, final Class<?>... paramTypes) throws Exception {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>() {
@Override
public Boolean run() throws Exception {
Method m;
try {
m = handlerType.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
if (logger.isDebugEnabled()) {
logger.debug(
"Class {} missing method {}, assume we can not skip execution", handlerType, methodName, e);
}
return false;
}
// @Skip的作用,就是标志着当前类是否被重写
// 如果方法存在@Skip,那么就代表当前类没有被重写
// 如果方法没有存在@Skip,那么就代表当前类被重写
return m != null && m.isAnnotationPresent(Skip.class);
}
});
}
mask0方法总结
以channelRegistered方法为例
如果一个handler实现了channelRegistered的方法,使用**
isSkippable
方法进行判断
因为实现了channelRegistered,那么父类的注解失效,即当前类上没有Skip注解,那么就将mask代表着channelRegistered**方法的位置为1ChannelInboundHandlerAdapter的入站处理方法和ChannelOutboundHandlerAdapter的出站处理方法都被Skip注解进行标记
pipeline会调用到**
io.netty.channel.AbstractChannelHandlerContext#fireChannelRegistered
**方法
@Override
public ChannelHandlerContext fireChannelRegistered() {
// 将channelRegistered的标志位传入
invokeChannelRegistered(findContextInbound(MASK_CHANNEL_REGISTERED));
return this;
}
AbstractChannelHandlerContext#findContextInbound方法整理
/**
*
* @param mask 表示要查找的 对应的操作位
* @return 查找到的handler
*/
private AbstractChannelHandlerContext findContextInbound(int mask) {
AbstractChannelHandlerContext ctx = this;
EventExecutor currentExecutor = executor();
do {
ctx = ctx.next;
} while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_INBOUND));
return ctx;
}
/**
* 这个方法返回 true,表示跳过这个 ctx,继续从 流水线 中查找下一个。
* @param ctx handler对应pipeline中的节点
* @param currentExecutor 当前处理任务的执行器
* @param mask 判断handler实现的方法标志
* @param onlyMask 表示大的方向,是出站,还是 入站
* @return true表示跳过
*/
private static boolean skipContext(
AbstractChannelHandlerContext ctx, EventExecutor currentExecutor, int mask, int onlyMask) {
// (onlyMask | mask)主要处理的是异常方法的判断
// 如果handler实现了mask代表的方法,那么notSameType就为false
boolean notSameType = (ctx.executionMask & (onlyMask | mask)) == 0;
// 当前线程的时候,才会考虑是否跳过 ctx,目标处理器的线程不是当前线程,也跳过
// 只有当 ctx.executor() 是 currentExecutor 当前线程的时候,才会考虑是否跳过 ctx,因为我们要保证事件处理的顺序。
boolean sameThreadAndNotDefined = ctx.executor() == currentExecutor && (ctx.executionMask & mask) == 0;
return notSameType || sameThreadAndNotDefined;
}