Netty源码分析第4章(pipeline)—->第3节: handler的删除

释放双眼,带上耳机,听听看~!

 

Netty源码分析第四章: pipeline

 

第三节: handler的删除

 

 

上一小节我们学习了添加handler的逻辑操作, 这一小节我们学习删除handler的相关逻辑

 

如果用户在业务逻辑中进行ctx.pipeline().remove(this)这样的写法, 或者ch.pipeline().remove(new SimpleHandler())这样的写法, 则就是对handler进行删除, 我们学习过添加handler的逻辑, 所以对handler删除操作理解起来也会比较容易

我们首先跟到defaultChannelPipeline的remove(handler)的方法中:


1
2
3
4
5
1public final ChannelPipeline remove(ChannelHandler handler) {
2    remove(getContextOrDie(handler));
3    return this;
4}
5

方法体里有个remove()方法, 传入一个 
getContextOrDie(handler) 参数, 这个 
getContextOrDie(handler) , 其实就是根据handler拿到其包装类HandlerContext对象

我们跟到getContextPrDie这个方法中:


1
2
3
4
5
1private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
2    AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
3    //代码省略
4}
5

这里仍然会通过context(handler)方法去寻找, 再跟进去:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1public final ChannelHandlerContext context(ChannelHandler handler) {
2    if (handler == null) {
3        throw new NullPointerException("handler");
4    }
5    //从头遍历节点
6    AbstractChannelHandlerContext ctx = head.next;
7    for (;;) {
8        if (ctx == null) {
9            return null;
10        }
11        //找到handler
12        if (ctx.handler() == handler) {
13            return ctx;
14        }
15        ctx = ctx.next;
16    }
17}
18

这里我们看到寻找的方法也非常的简单, 就是从头结点开始遍历, 遍历到如果其包装的handler对象是传入的handler对象, 则返回找到的handlerContext

 

回到remove(handler)方法:


1
2
3
4
5
1public final ChannelPipeline remove(ChannelHandler handler) {
2    remove(getContextOrDie(handler));
3    return this;
4}
5

继续跟到remove方法中:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
2
3    //当前删除的节点不能是head, 也不能是tail
4    assert ctx != head && ctx != tail;
5
6    synchronized (this) {
7        //执行删除操作
8        remove0(ctx);
9        if (!registered) {
10            callHandlerCallbackLater(ctx, false);
11            return ctx;
12        }
13
14        //回调删除handler事件
15        EventExecutor executor = ctx.executor();
16        if (!executor.inEventLoop()) {
17            executor.execute(new Runnable() {
18                @Override
19                public void run() {
20                    callHandlerRemoved0(ctx);
21                }
22            });
23            return ctx;
24        }
25    }
26    callHandlerRemoved0(ctx);
27    return ctx;
28}
29

首先要断言删除的节点不能是tail和head

然后通过remove0(ctx)进行实际的删除操作, 跟到remove0(ctx)中:


1
2
3
4
5
6
7
8
9
10
11
1private static void remove0(AbstractChannelHandlerContext ctx) {
2    //当前节点的前置节点
3    AbstractChannelHandlerContext prev = ctx.prev;
4    //当前节点的后置节点
5    AbstractChannelHandlerContext next = ctx.next;
6    //前置节点的下一个节点设置为后置节点
7    prev.next = next;
8    //后置节点的上一个节点设置为前置节点
9    next.prev = prev;
10}
11

这里的操作也非常简单, 做了一个指针移动的操作, 熟悉双向链表的小伙伴应该不会陌生, 删除节点逻辑大概如下图所示:

Netty源码分析第4章(pipeline)---->第3节: handler的删除

4-3-1

回到remove(ctx)方法:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
2
3    //当前删除的节点不能是head, 也不能是tail
4    assert ctx != head && ctx != tail;
5
6    synchronized (this) {
7        //执行删除操作
8        remove0(ctx);
9        if (!registered) {
10            callHandlerCallbackLater(ctx, false);
11            return ctx;
12        }
13
14        //回调删除handler事件
15        EventExecutor executor = ctx.executor();
16        if (!executor.inEventLoop()) {
17            executor.execute(new Runnable() {
18                @Override
19                public void run() {
20                    callHandlerRemoved0(ctx);
21                }
22            });
23            return ctx;
24        }
25    }
26    callHandlerRemoved0(ctx);
27    return ctx;
28}
29

我们继续往下看, 如果当前线程不是eventLoop线程则将回调删除事件封装成task放在taskQueue中让eventLoop线程进行执行, 否则, 则直接执行回调删除事件

跟到callHandlerRemoved0(ctx)方法中:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
2    try {
3        try {
4            //调用handler的handlerRemoved方法
5            ctx.handler().handlerRemoved(ctx);
6        } finally {
7            //将当前节点状态设置为已移除
8            ctx.setRemoved();
9        }
10    } catch (Throwable t) {
11        fireExceptionCaught(new ChannelPipelineException(
12                ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
13    }
14}
15

与添加handler的逻辑一样, 这里会调用当前handler的handlerRemoved方法, 如果用户没有重写该方法, 则会调用其父类的方法, 方法体在ChannelHandlerAdapter类中有定义, 我们跟进去


1
2
3
4
1public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
2    
3}
4

同添加handler一样, 也是一个空实现, 这里用户可以通过重写来添加自己需要的逻辑

以上就是删除handler的相关操作

 

上一节: handler的添加

下一节: 传播inbound事件

 

给TA打赏
共{{data.count}}人
人已打赏
安全网络

CDN安全市场到2022年价值76.3亿美元

2018-2-1 18:02:50

安全技术

《React后台管理系统实战 :一》:目录结构、引入antd、引入路由、写login页面、使用antd的form登录组件、form前台验证、高阶函数/组件

2021-12-21 16:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索