温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

handler在pipeline当如何存储

发布时间:2021-12-16 16:44:37 来源:亿速云 阅读:85 作者:iii 栏目:云计算

这篇文章主要介绍“handler在pipeline当如何存储”,在日常操作中,相信很多人在handler在pipeline当如何存储问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”handler在pipeline当如何存储”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

今天解决2个问题,

1、handler在pipeline当中究竟是如何存储的;

2、在遍历handler的过程中,会根据event的不同,调用不同的handler,这一点是如何实现的。

先研究第一个问题:

TailHandler tailHandler = new TailHandler();
tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);

HeadHandler headHandler = new HeadHandler(channel.unsafe());
head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);

head.next = tail;
tail.prev = head;

这是DefaultChannelPipeline构造函数当中的一段代码,我们之前提到过,在pipeline当中存在一个双向链表,这里就是把双向链表的头和尾进行了初始化。

之后我们通过addlast方法向pipeline当中添加handler,

DefaultChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;

这里就是把一个新的handler加入到双向链表当中去。

另一个问题,双向链表当中的元素究竟是什么,

DefaultChannelHandlerContext newCtx =
                    new DefaultChannelHandlerContext(this, invoker, name, handler);

需要看这个,简单理解,把handler放到了一个新的 DefaultChannelHandlerContext 当中。那么它的作用究竟是什么呢?

通过对代码的研究, DefaultChannelHandlerContext其实是一个动态代理类,而我们的各个handler,就是被代理的类。这里有两点需要解释一下。先看下面这段代码

    @Override
    public ChannelFuture write(Object msg, ChannelPromise promise) {
        DefaultChannelHandlerContext next = findContextOutbound(MASK_WRITE);
        next.invoker.invokeWrite(next, msg, promise);
        return promise;
    }

首先,不要被write方法所迷惑,这个方法里面确实执行的write的动作,以及write当中所包含的encode的动作。但是请注意,这个write动作,并不是当前元素的write,而是链表当中下一个元素当中的handler的write,在handler的write方法的末尾,会执行next.write,这里又会执行再下一个元素当中的handler的write。依次类推,实现了链表的遍历。

其次:不要被invoke所迷惑,这里并没有用到java的反射机制,因为 不论你传入什么样的handler,都来自ChannelHandler这个统一的老祖宗。按需要调用不同的方法即可。跟反射一毛钱关系都没有。

然后是第二个问题:

首先明确一个概念:所有的handler来自同一个祖宗ChannelHandler ,而 ChannelHandler 当中的不同方法,对应了netty当中各个不同的事件。

我们在初始化bootstrap的时候,加入了很多个handler,有些负责下行的decode,有些负责上行的encode,我们当然希望,下行的时候,只进入下行相关的handler,上行的时候,只进入上行相关的handler。那么具体是怎么做到的呢?看下面这段代码,鉴于篇幅问题,只摘录了其中一段:

if (handlerType.getMethod(
    "handlerAdded", ChannelHandlerContext.class).isAnnotationPresent(Skip.class)) {
    flags |= MASK_HANDLER_ADDED;
}

在构造一个 DefaultChannelHandlerContext,会有这样的一段代码,我们可以这样理解这段语句:根据handler当中不通方法的注解,来判定当发生某个event的时候,该方法是否执行。

ChannelHandlerAdapter 是 ChannelHandler 一个最基础的实现,我们看一下 ChannelHandlerAdapter 的代码,会发现,每一个方法头部,都会有一个@Skip的注解。也就是说,默认情况下,每一个方法都不会被执行。而在 ChannelHandlerAdapter 的子孙当中,Override了某一个方法, @Skip 就没有了。那么这个handler的这个方法,就会被执行。

至于具体的判定过程,可以参照另一个篇文章android edittext.setInputType,当中按位进行设置的思想。

到此,关于“handler在pipeline当如何存储”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI