伙伴云客服论坛»论坛 S区 S软件开发 查看内容

0 评论

0 收藏

分享

Netty分布式pipeline管道Handler的删除逻辑操作

目录

    删除handler操作
      我们跟到getContextPrDie这个方法中首先要断言删除的节点不能是tail和head回到remove(ctx)方法


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

删除handler操作

假设用户在业务逻辑中停止ctx.pipeline().remove(this)这样的写法, 或者ch.pipeline().remove(new SimpleHandler())这样的写法, 则就是对handler停止删除, 我们学习过添加handler的逻辑, 所以对handler删除操作理解起来也会比较容易
我们首先跟到defaultChannelPipeline的remove(handler)的方法中:
  1. public final ChannelPipeline remove(ChannelHandler handler) {
  2.     remove(getContextOrDie(handler));
  3.     return this;
  4. }
复制代码
方法体里有个remove()方法, 传入一个 getContextOrDie(handler) 参数, 这个 getContextOrDie(handler) , 其实就是根据handler拿到其包装类HandlerContext对象

我们跟到getContextPrDie这个方法中
  1. private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
  2.     AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
  3.     //代码省略
  4. }
复制代码
这里仍然会通过context(handler)方法去寻找, 再跟进去:
  1. public 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. }
复制代码
这里我们看到寻找的方法也非常的简单, 就是从头结点开端遍历, 遍历到假设其包装的handler对象是传入的handler对象, 则返回找到的handlerContext
回到remove(handler)方法:
  1. public final ChannelPipeline remove(ChannelHandler handler) {
  2.     remove(getContextOrDie(handler));
  3.     return this;
  4. }
复制代码
继续跟到remove方法中:
  1. private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
  2.     //当前删除的节点不能是head, 也不能是tail
  3.     assert ctx != head && ctx != tail;
  4.     synchronized (this) {
  5.         //执行删除操作
  6.         remove0(ctx);
  7.         if (!registered) {
  8.             callHandlerCallbackLater(ctx, false);
  9.             return ctx;
  10.         }
  11.         //回调删除handler事件
  12.         EventExecutor executor = ctx.executor();
  13.         if (!executor.inEventLoop()) {
  14.             executor.execute(new Runnable() {
  15.                 @Override
  16.                 public void run() {
  17.                     callHandlerRemoved0(ctx);
  18.                 }
  19.             });
  20.             return ctx;
  21.         }
  22.     }
  23.     callHandlerRemoved0(ctx);
  24.     return ctx;
  25. }
复制代码
首先要断言删除的节点不能是tail和head

然后通过remove0(ctx)停止实际的删除操作, 跟到remove0(ctx)中:
  1. private 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. }
复制代码
这里的操作也非常简单, 做了一个指针挪动的操作, 熟悉双向链表的小伙伴应该不会陌生, 删除节点逻辑大约如下图所示:
Netty分布式pipeline管道Handler的删除逻辑操作-1.png


回到remove(ctx)方法
  1. private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
  2.     //当前删除的节点不能是head, 也不能是tail
  3.     assert ctx != head && ctx != tail;
  4.     synchronized (this) {
  5.         //执行删除操作
  6.         remove0(ctx);
  7.         if (!registered) {
  8.             callHandlerCallbackLater(ctx, false);
  9.             return ctx;
  10.         }
  11.         //回调删除handler事件
  12.         EventExecutor executor = ctx.executor();
  13.         if (!executor.inEventLoop()) {
  14.             executor.execute(new Runnable() {
  15.                 @Override
  16.                 public void run() {
  17.                     callHandlerRemoved0(ctx);
  18.                 }
  19.             });
  20.             return ctx;
  21.         }
  22.     }
  23.     callHandlerRemoved0(ctx);
  24.     return ctx;
  25. }
复制代码
我们继续往下看, 假设当前线程不是eventLoop线程则将回调删除事件封装成task放在taskQueue中让eventLoop线程停止执行, 否则, 则直接执行回调删除事件
跟到callHandlerRemoved0(ctx)方法中:
  1. private 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. }
复制代码
与添加handler的逻辑一样, 这里会调用当前handler的handlerRemoved方法, 假设用户没有重写该方法, 则会调用其父类的方法, 方法体在ChannelHandlerAdapter类中有定义, 我们跟进去
  1. public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
  2. }
复制代码
同添加handler一样, 也是一个空实现, 这里用户可以通过重写来添加自己需要的逻辑
以上就是删除handler的相关操作,更多关于Netty分布式pipeline管道删除Handler的资料请关注网站其它相关文章!

回复

举报 使用道具

全部回复
暂无回帖,快来参与回复吧
本版积分规则 高级模式
B Color Image Link Quote Code Smilies

艺桦
注册会员
主题 14
回复 17
粉丝 0
|网站地图
快速回复 返回顶部 返回列表