Netty的ChannelPipline传播源码解析

2021/7/21 17:11:32

本文主要是介绍Netty的ChannelPipline传播源码解析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

将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中没有被注解注解的方法掩码!



这篇关于Netty的ChannelPipline传播源码解析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程