NChannelPipline传播源码解析

值友2838668266 07-21 16:19 关注

将Handler封装为包装对象

newCtx = newContext(group, filterName(name, handler), handler);

这里比较难理解的就是这个,我们进入到newContext方法里面:

private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}

进入到 DefaultChannelHandlerContext类的源码里面:

DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
//调用父类进行掩码计算
super(pipeline, executor, name, handler.getClass());
//保存一个handler
this.handler = handler;
}

这里除了会保存一个handler还会调用父类,我们介入到父类里面:

AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,
String name, Class handlerClass) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor;
//标识 是in还是out
this.executionMask = mask(handlerClass);
// 如果由EventLoop或给定的Executor驱动的驱动程序是OrderedEventExecutor的实例,则其顺序为。
ordered = executor == null || executor instanceof OrderedEventExecutor;
}

这里会保存一些属性,这些属性都是我们前面讲过的,大家自行分析下,我们重点关注掩码的计算:

this.executionMask = mask(handlehttp://www.diuxie.comrClass);
static int mask(Class clazz) {
//直接再缓存中取出
Map, Integer> cache = MASKS.get();
Integer mask = cache.get(clazz);
//缓存中不存在
if (mask == null) {
mask = mask0(clazz);
cache.put(clazz, mask);
}
return mask;
}

先从缓存中取出,如果不存在就调用 mask0(clazz); 方法计算,然后再放进缓存,我们进入到 mask0(clazz);方法:

private static int mask0(Class handlerType) {
int mask = MASK_EXCEPTION_CAUGHT;
try {
if (ChannelInboundHandler.class.isAssignableFrom(handlerType)) {
// 如果是 ChannelInboundHandler 实例,所有 Inbound 事件置为 1
mask |= MASK_ALL_INBOUND;
//判断是否存在Skip注解 如果催你在这个跳过的注解 就移除这个
if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_REGISTERED;
}
..................忽略类似的代码.....................
}
if (ChannelOutboundHandler.class.isAssignableFrom(handlerType)) {
mask |= MASK_ALL_OUTBOUND;
if (isSkippable(handlerType, "bind", ChannelHandlerContext.class,
SocketAddress.class, ChannelPromise.class)) {
mask &= ~MASK_BIND;
}
..................忽略类似的手游代码.....................
}
} catch (Exception e) {
..................忽略异常的代码.....................
}
return mask;
}

这会区分两种情况,一种是 ChannelInboundHandler类型的,一种是 ChannelOutboundHandler类型的,二者逻辑相同,我们以ChannelInboundHandler为例:

首先,再ChannelHandlerMask类里面定义了很多的预设掩码值:

/**
* 以下是方法代表的掩码值
*/
static final int MASK_EXCEPTION_CAUGHT = 1;
/**
* channelRegistered方法的掩码
*/
static final int MASK_CHANNEL_REGISTERED = 1 << 1;
/**
* channelUnregistered方法的掩码
*/
static final int MASK_CHANNEL_UNREGISTERED = 1 << 2;
/**

* 后面的以此类推

NChannelPipline传播源码解析

文章图片来源:手游http://www.diuxie.com/ 手游


static final int MASK_CHANNEL_ACTIVE = 1 << 3;

static final int MASK_CHANNEL_INACTIVE = 1 << 4;

static final int MASK_CHANNEL_READ = 1 << 5;
static final int MASK_CHANNEL_READ_COMPLETE = 1 << 6;
static final int MASK_USER_EVENT_TRIGGERED = 1 << 7;
static final int MASK_CHANNEL_WRITABILITY_CHANGED = 1 << 8;
/**
* bind方法的掩码
*/
static final int MASK_BIND = 1 << 9;
/**
* connect方法的掩码
*/
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;
/**
* 包含全部 Inbound方法的掩码
*/
private static final int MASK_ALL_INBOUND = MASK_EXCEPTION_CAUGHT | 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;
/**
* 包含全部 outbound方法的掩码
*/
private static final int MASK_ALL_OUTBOUND = MASK_EXCEPTION_CAUGHT | MASK_BIND | MASK_CONNECT | MASK_DISCONNECT |
MASK_CLOSE | MASK_DEREGISTER | MASK_READ | MASK_WRITE | MASK_FLUSH;

我们回到 mask0方法:

mask |= MASK_ALL_INBOUND;

一开始,我们会直接将一个handler的掩码计算为拥有全部方法的掩码!

if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
mask &= ~MASK_CHANNEL_REGISTERED;
}

判断该方法是否存在 Skip注解,如果存在就排除掉这个掩码!

整个逻辑执行完毕后,这个掩码就只会包含handler中没有被注解注解的方法掩码!

暂无评论,打开APP参与讨论