相关文章链接
processSelectedKeys() vs runAllTasks()
NioServerSocketChannel-Unsafe初始化详解
executionMask
一、executionMask 是什么?
1.1 定义
executionMask 是 ChannelHandlerContext 的一个整型字段,用位掩码的方式记录当前 Handler 实现了哪些方法。
// AbstractChannelHandlerContext.java
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext {
// 执行掩码:标识这个 Handler 实现了哪些方法
private final int executionMask;
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);
// ...
}
}
1.2 为什么需要 executionMask?
性能优化! 避免不必要的方法调用。
没有 executionMask 的情况:
// 每次事件传播都要调用 Handler 的方法
handler.channelRead(ctx, msg); // 即使 Handler 没有重写这个方法
有 executionMask 的情况:
// 先检查 Handler 是否实现了这个方法
if ((ctx.executionMask & MASK_CHANNEL_READ) != 0) {
handler.channelRead(ctx, msg); // 只有实现了才调用
} else {
// 直接跳过,继续传播
ctx.fireChannelRead(msg);
}
二、executionMask 的计算过程
2.1 掩码常量定义
// ChannelHandlerMask.java
public final class ChannelHandlerMask {
// 入站事件掩码
static final int MASK_EXCEPTION_CAUGHT = 1; // 0000 0001
static final int MASK_CHANNEL_REGISTERED = 1 << 1; // 0000 0010
static final int MASK_CHANNEL_UNREGISTERED = 1 << 2; // 0000 0100
static final int MASK_CHANNEL_ACTIVE = 1 << 3; // 0000 1000
static final int MASK_CHANNEL_INACTIVE = 1 << 4; // 0001 0000
static final int MASK_CHANNEL_READ = 1 << 5; // 0010 0000
static final int MASK_CHANNEL_READ_COMPLETE = 1 << 6; // 0100 0000
static final int MASK_USER_EVENT_TRIGGERED = 1 << 7; // 1000 0000
static final int MASK_CHANNEL_WRITABILITY_CHANGED = 1 << 8;
// 出站事件掩码
static final int MASK_BIND = 1 << 9;
static final int MASK_CONNECT = 1 << 10;
static final int MASK_DISCONNECT = 1 << 11;
static final int MASK_CLOSE = 1 << 12;
static final int MASK_DEREGISTER = 1 << 13;
static final int MASK_READ = 1 << 14;
static final int MASK_WRITE = 1 << 15;
static final int MASK_FLUSH = 1 << 16;
// 所有入站事件的掩码(OR 运算)
static final int MASK_ONLY_INBOUND =
MASK_CHANNEL_REGISTERED |
MASK_CHANNEL_UNREGISTERED |
MASK_CHANNEL_ACTIVE |
MASK_CHANNEL_INACTIVE |
MASK_CHANNEL_READ |
MASK_CHANNEL_READ_COMPLETE |
MASK_USER_EVENT_TRIGGERED |
MASK_CHANNEL_WRITABILITY_CHANGED |
MASK_EXCEPTION_CAUGHT;
// 所有出站事件的掩码(OR 运算)
static final int MASK_ONLY_OUTBOUND =
MASK_BIND |
MASK_CONNECT |
MASK_DISCONNECT |
MASK_CLOSE |
MASK_DEREGISTER |
MASK_READ |
MASK_WRITE |
MASK_FLUSH;
}
2.2 计算 Handler 的 executionMask
当 Handler 被添加到 Pipeline 时,Netty 会扫描 Handler 类,检查它实现了哪些方法:
// ChannelHandlerMask.java
static int mask(Class<? extends ChannelHandler> clazz) {
// 尝试从缓存中获取
Map<Class<? extends ChannelHandler>, Integer> cache = MASKS.get();
Integer mask = cache.get(clazz);
if (mask == null) {
// 计算掩码
mask = mask0(clazz);
cache.put(clazz, mask);
}
return mask;
}
private static int mask0(Class<? extends ChannelHandler> handlerType) {
int mask = MASK_EXCEPTION_CAUGHT; // 默认包含异常处理
try {
// 检查是否是 ChannelInboundHandler
if (ChannelInboundHandler.class.isAssignableFrom(handlerType)) {
mask |= MASK_ALL_INBOUND; // 先假设实现了所有入站方法
// 检查每个入站方法是否被重写
if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
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, "userEventTriggered", ChannelHandlerContext.class, Object.class)) {
mask &= ~MASK_USER_EVENT_TRIGGERED;
}
if (isSkippable(handlerType, "channelWritabilityChanged", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_WRITABILITY_CHANGED;
}
}
// 检查是否是 ChannelOutboundHandler
if (ChannelOutboundHandler.class.isAssignableFrom(handlerType)) {
// 类似的检查出站方法...
}
} catch (Exception e) {
// 异常时返回所有掩码
return MASK_ALL_INBOUND | MASK_ALL_OUTBOUND;
}
return mask;
}
// 检查方法是否可以跳过(没有被重写)
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 = handlerType.getMethod(methodName, paramTypes);
// 检查方法是否被 @Skip 注解标记,或者是否在基类中定义
return m.isAnnotationPresent(Skip.class) ||
m.getDeclaringClass().equals(ChannelInboundHandlerAdapter.class) ||
m.getDeclaringClass().equals(ChannelOutboundHandlerAdapter.class) ||
m.getDeclaringClass().equals(ChannelDuplexHandler.class);
}
});
}
2.3 实际示例
示例 1:只实现了 channelRead
public class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("收到消息: " + msg);
ctx.fireChannelRead(msg);
}
// 其他方法都没有重写
}
计算 executionMask:
初始值:MASK_EXCEPTION_CAUGHT = 0000 0001
检查 ChannelInboundHandler:
先设置所有入站位:mask |= MASK_ALL_INBOUND
检查 channelRegistered:没重写,清除该位
检查 channelUnregistered:没重写,清除该位
检查 channelActive:没重写,清除该位
检查 channelInactive:没重写,清除该位
检查 channelRead:重写了,保留该位 ✓
检查 channelReadComplete:没重写,清除该位
检查 userEventTriggered:没重写,清除该位
检查 channelWritabilityChanged:没重写,清除该位
最终 executionMask = MASK_EXCEPTION_CAUGHT | MASK_CHANNEL_READ
= 0000 0001 | 0010 0000
= 0010 0001
示例 2:实现了多个方法
public class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("连接激活");
ctx.fireChannelActive();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("收到消息: " + msg);
ctx.fireChannelRead(msg);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("连接断开");
ctx.fireChannelInactive();
}
}
计算 executionMask:
最终 executionMask = MASK_EXCEPTION_CAUGHT |
MASK_CHANNEL_ACTIVE |
MASK_CHANNEL_READ |
MASK_CHANNEL_INACTIVE
= 0000 0001 | 0000 1000 | 0010 0000 | 0001 0000
= 0011 1001
1810



被折叠的 条评论
为什么被折叠?



