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

 更新时间:2022年03月28日 10:35:53   作者:向南是个万人迷  
这篇文章主要为大家介绍了Netty分布式pipeline管道Handler的删除逻辑操作,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

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

删除handler操作

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

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

public final ChannelPipeline remove(ChannelHandler handler) {
    remove(getContextOrDie(handler));
    return this;
}

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

我们跟到getContextPrDie这个方法中

private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
    AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
    //代码省略
}

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

public final ChannelHandlerContext context(ChannelHandler handler) {
    if (handler == null) {
        throw new NullPointerException("handler");
    }
    //从头遍历节点
    AbstractChannelHandlerContext ctx = head.next;
    for (;;) {
        if (ctx == null) {
            return null;
        }
        //找到handler
        if (ctx.handler() == handler) {
            return ctx;
        }
        ctx = ctx.next;
    }
}

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

回到remove(handler)方法:

public final ChannelPipeline remove(ChannelHandler handler) {
    remove(getContextOrDie(handler));
    return this;
}

继续跟到remove方法中:

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
    //当前删除的节点不能是head, 也不能是tail
    assert ctx != head && ctx != tail;
    synchronized (this) {
        //执行删除操作
        remove0(ctx);
        if (!registered) {
            callHandlerCallbackLater(ctx, false);
            return ctx;
        }
        //回调删除handler事件
        EventExecutor executor = ctx.executor();
        if (!executor.inEventLoop()) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    callHandlerRemoved0(ctx);
                }
            });
            return ctx;
        }
    }
    callHandlerRemoved0(ctx);
    return ctx;
}

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

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

private static void remove0(AbstractChannelHandlerContext ctx) {
    //当前节点的前置节点
    AbstractChannelHandlerContext prev = ctx.prev;
    //当前节点的后置节点
    AbstractChannelHandlerContext next = ctx.next;
    //前置节点的下一个节点设置为后置节点
    prev.next = next;
    //后置节点的上一个节点设置为前置节点
    next.prev = prev;
}

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

回到remove(ctx)方法

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
    //当前删除的节点不能是head, 也不能是tail
    assert ctx != head && ctx != tail;
    synchronized (this) {
        //执行删除操作
        remove0(ctx);
        if (!registered) {
            callHandlerCallbackLater(ctx, false);
            return ctx;
        }
        //回调删除handler事件
        EventExecutor executor = ctx.executor();
        if (!executor.inEventLoop()) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    callHandlerRemoved0(ctx);
                }
            });
            return ctx;
        }
    }
    callHandlerRemoved0(ctx);
    return ctx;
}

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

跟到callHandlerRemoved0(ctx)方法中:

private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
    try {
        try {
            //调用handler的handlerRemoved方法
            ctx.handler().handlerRemoved(ctx);
        } finally {
            //将当前节点状态设置为已移除
            ctx.setRemoved();
        }
    } catch (Throwable t) {
        fireExceptionCaught(new ChannelPipelineException(
                ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
    }
}

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

public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
}

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

以上就是删除handler的相关操作,更多关于Netty分布式pipeline管道删除Handler的资料请关注脚本之家其它相关文章!

相关文章

  • java底层JDK Logging日志模块处理细节深入分析

    java底层JDK Logging日志模块处理细节深入分析

    这篇文章主要为大家介绍了java底层JDK Logging日志模块处理细节深入分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • java:无法访问org.springframework.boot.SpringApplication的解决方法

    java:无法访问org.springframework.boot.SpringApplication的解决方法

    这篇文章主要给大家介绍了关于java:无法访问org.springframework.boot.SpringApplication的解决方法,文中通过实例代码将解决的办法介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • Spring Boot拦截器和过滤器实例解析

    Spring Boot拦截器和过滤器实例解析

    这篇文章主要介绍了Spring Boot拦截器和过滤器实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • SpringBoot集成JWT实现登陆验证的方法详解

    SpringBoot集成JWT实现登陆验证的方法详解

    JSON Web Token(JWT)是一个开放的标准(RFC 7519),它定义了一个紧凑且自包含的方式,用于在各方之间以JSON对象安全地传输信息。本文将利用SpringBoot集成JWT实现登陆验证,感兴趣的可以了解一下
    2022-05-05
  • Java递归造成的堆栈溢出问题及解决方案

    Java递归造成的堆栈溢出问题及解决方案

    在Java中,递归造成的堆栈溢出问题通常是因为递归调用的深度过大,导致调用栈空间不足,解决这类问题的一种常见方法是使用非递归的方式重写算法,即使用迭代替代递归,需要的朋友可以参考下
    2024-08-08
  • Java的HashMap源码解析

    Java的HashMap源码解析

    这篇文章主要介绍了Java的HashMap源码解析,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对是一个Node,后台是用一个Node数组来存放数据,这个Node数组就是HashMap的主干,需要的朋友可以参考下
    2023-11-11
  • java中对字符串每个字符统计的方法

    java中对字符串每个字符统计的方法

    java中对字符串每个字符统计的方法,需要的朋友可以参考一下
    2013-03-03
  • @MapperScan注解与@Mapper注解的使用

    @MapperScan注解与@Mapper注解的使用

    这篇文章主要介绍了@MapperScan注解与@Mapper注解的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 部署Java在服务器端的EJB组件的方法

    部署Java在服务器端的EJB组件的方法

    这篇文章主要介绍了部署Java在服务器端的EJB组件的方法,同时给出了简单的客户端调用方法,需要的朋友可以参考下
    2015-11-11
  • SpringBoot项目中忽略某属性返回数据给前端

    SpringBoot项目中忽略某属性返回数据给前端

    在Spring Boot中,保护敏感信息和减少数据传输是很重要的,我们可以使用多种方法来忽略返回数据中的字段,无论是使用@JsonIgnore注解、Projection投影、@JsonIgnoreProperties注解还是自定义序列化器,都能达到我们的目的,在实际应用中,根据具体场景和需求选择合适的方法
    2024-05-05

最新评论