将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<? extends ChannelHandler> 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<? 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; }
先从缓存中取出,如果不存在就调用 mask0(clazz); 方法计算,然后再放进缓存,我们进入到 mask0(clazz);
方法:
private static int mask0(Class<? extends ChannelHandler> 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; /** * 后面的以此类推 */ 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中没有被注解注解的方法掩码!