我的编程空间,编程开发者的网络收藏夹
学习永远不晚

netty中pipeline的handler添加删除分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

netty中pipeline的handler添加删除分析

添加

ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workGroup)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>(){
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new MyServerHandler());
            }
        });
ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
channelFuture.channel().closeFuture().sync();

分析pipeline.addLast(new MyServerHandler())中的addLast

首先通过channel拿到当前的pipline, 拿到pipeline之后再为其添加handler, 因为channel初始化默认创建的是DefualtChannelPipeline

DefaultChannelPipeline.addLast(ChannelHandler... handlers)

public final ChannelPipeline addLast(ChannelHandler... handlers) {
    return addLast(null, handlers);
}
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
    if (handlers == null) {
        throw new NullPointerException("handlers");
    }
    for (ChannelHandler h: handlers) {
        if (h == null) {
            break;
        }
        addLast(executor, null, h);
    }
    return this;
}

这里的handlers只有一个

public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
    final AbstractChannelHandlerContext newCtx;
    synchronized (this) {
        //判断handler是否被重复添加(1)
        checkMultiplicity(handler);
        //创建一个HandlerContext并添加到列表(2)
        newCtx = newContext(group, filterName(name, handler), handler);
        //添加HandlerContext(3)
        addLast0(newCtx);
        //是否已注册
        if (!registered) {
            newCtx.setAddPending();
            callHandlerCallbackLater(newCtx, true);
            return this;
        }
        EventExecutor executor = newCtx.executor();
        if (!executor.inEventLoop()) {
            newCtx.setAddPending();
            //回调用户事件
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    callHandlerAdded0(newCtx);
                }
            });
            return this;
        }
    }
    //回调添加事件(4)
    callHandlerAdded0(newCtx);
    return this;
}

分为四个步骤:

  • 重复添加验证
  • 创建一个HandlerContext并添加到列表
  • 添加context
  • 回调添加事件

checkMultiplicity(handler)重复添加验证

private static void checkMultiplicity(ChannelHandler handler) {
    if (handler instanceof ChannelHandlerAdapter) {
        ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler; 
        if (!h.isSharable() && h.added) {
            throw new ChannelPipelineException(
                    h.getClass().getName() +
                    " is not a @Sharable handler, so can't be added or removed multiple times.");
        }
        //满足条件设置为true, 代表已添加
        h.added = true;
    }
}
  • 首先判断是不是ChannelHandlerAdapter类型, 因为我们自定义的handler通常会直接或者间接的继承该接口, 所以这里为true拿到handler之后转换成ChannelHandlerAdapter类型。
  • 然后进行条件判断 if (!h.isSharable() && h.added) 代表如果不是共享的handler, 并且是未添加状态, 则抛出异常。

isSharable()

public boolean isSharable() { 
    Class<?> clazz = getClass();
    Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
    Boolean sharable = cache.get(clazz);
    if (sharable == null) { 
        //如果这个类注解了Sharable.class, 说明这个类会被多个channel共享
        sharable = clazz.isAnnotationPresent(Sharable.class);
        cache.put(clazz, sharable);
    }
    return sharable;
}
  • 首先拿到当前handlerclass对象。
  • 然后再从netty自定义的一个ThreadLocalMap对象中获取一个盛放handlerclass对象的map, 并获取其value
  • 如果value值为空, 则会判断是否被Sharable注解, 并将自身handlerclass对象和判断结果存入map对象中, 最后返回判断结果。
  • 这说明了被Sharable注解的handler是一个共享handler
  • 从这个逻辑我们可以判断, 共享对象是可以重复添加的。

回到DefaultChannelPipeline.addLast,如果是共享对象或者没有被添加, 则将ChannelHandlerAdapteradded设置为true, 代表已添加分析完了重复添加验证, 回到addLast方法中, 我们看第二步, 创建一个HandlerContext并添加到列表

newCtx = newContext(group, filterName(name, handler), handler)

newCtx = newContext(group, filterName(name, handler), handler)

首先看filterName(name, handler)方法, 这个方法是判断添加handler的name是否重复

filterName(name, handler)

首先看filterName(name, handler)方法, 这个方法是判断添加handlername是否重复

private String filterName(String name, ChannelHandler handler) {
    if (name == null) {
        //没有名字创建默认名字
        return generateName(handler);
    }
    //检查名字是否重复
    checkDuplicateName(name);
    return name;
}

因为我们添加handler时候, 不一定会给handler命名, 所以这一步name有可能是null, 如果是null, 则创建一个默认的名字, 这里创建名字的方法就不分析了

checkDuplicateName(name)

private void checkDuplicateName(String name) {
    //不为空
    if (context0(name) != null) {
        throw new IllegalArgumentException("Duplicate handler name: " + name);
    }
}

继续跟进分析context0(name)方法

context0(name)

private AbstractChannelHandlerContext context0(String name) {
    //遍历pipeline
    AbstractChannelHandlerContext context = head.next;
    while (context != tail) {
        //发现name相同, 说明存在handler
        if (context.name().equals(name)) {
            //返回
            return context;
        }
        context = context.next;
    }
    return null;
}

这里的逻辑就是将pipeline中, 从head节点往下遍历HandlerContext, 一直遍历到tail, 如果发现名字相同则会认为重复并返回HandlerContext对象。

继续跟到newContext(group, filterName(name, handler), handler)方法中。

newContext(EventExecutorGroup group, String name, ChannelHandler handler)

private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
    return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}

可以看到创建了一个DefaultChannelHandlerContext对象, 构造方法的参数中, 第一个this代表当前的pipeline对象, groupnull, 所以childExecutor(group)也会返回null, namehandler的名字, handler为新添加的handler对象

new DefaultChannelHandlerContext(this, childExecutor(group), name, handler)

DefaultChannelHandlerContext(
        DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
    super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
    if (handler == null) {
        throw new NullPointerException("handler");
    }
    this.handler = handler;
}
  • 首先调用了父类的构造方法, 之后将handler赋值为自身handler的成员变量, HandlerConexthandler关系在此也展现了出来, 是一种组合关系
  • 父类的构造方法, 有这么两个参数:isInbound(handler), isOutbound(handler), 这两个参数意思是判断需要添加的handlerinboundHandler还是outBoundHandler

isInbound(handler)

private static boolean isInbound(ChannelHandler handler) {
    return handler instanceof ChannelInboundHandler;
}

这里通过是否实现ChannelInboundHandler接口来判断是否为inboundhandler

isOutbound(handler)

private static boolean isOutbound(ChannelHandler handler) {
    return handler instanceof ChannelOutboundHandler;
}

通过判断是否实现ChannelOutboundHandler接口判断是否为outboundhandler

在跟到其父类AbstractChannelHandlerContext的构造方法中

AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, 
                              boolean inbound, boolean outbound) {
    this.name = ObjectUtil.checkNotNull(name, "name");
    this.pipeline = pipeline;
    this.executor = executor;
    this.inbound = inbound;
    this.outbound = outbound;
    ordered = executor == null || executor instanceof OrderedEventExecutor;
}

之前tail节点和head节点创建的时候也执行到了这里,初始化了name, pipeline, 以及标识添加的handlerinboundhanlder还是outboundhandler

回到DefaultChannelPipeline.addLast,分析完了创建HandlerContext的相关逻辑, 我们继续跟第三步, 添加HandlerContext

addLast0(newCtx)

private void addLast0(AbstractChannelHandlerContext newCtx) {
    //拿到tail节点的前置节点
    AbstractChannelHandlerContext prev = tail.prev;
    //当前节点的前置节点赋值为tail节点的前置节点
    newCtx.prev = prev;
    //当前节点的下一个节点赋值为tail节点
    newCtx.next = tail;
    //tail前置节点的下一个节点赋值为当前节点
    prev.next = newCtx;
    //tail节点的前一个节点赋值为当前节点
    tail.prev = newCtx;
}

做了一个指针的指向操作, 将新添加的handlerConext放在tail节点之前, 之前tail节点的上一个节点之后, 如果是第一次添加handler, 那么添加后的结构入下图所示

添加完handler之后, 这里会判断当前channel是否已经注册, 这部分逻辑之后再进行分析,先接着继续执行。

之后会判断当前线程线程是否为eventLoop线程, 如果不是eventLoop线程, 就将添加回调事件封装成task交给eventLoop线程执行, 否则, 直接执行添加回调事件callHandlerAdded0(newCtx)

callHandlerAdded0(newCtx)

private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
    try {
        ctx.handler().handlerAdded(ctx);
        ctx.setAddComplete();
    } catch (Throwable t) {
        
    }
}

分析ctx.handler().handlerAdded(ctx),其中ctx是我们新创建的HandlerContext, 通过handler()方法拿到绑定的handler, 也就是新添加的handler, 然后执行handlerAdded(ctx)方法, 如果我们没有重写这个方法, 则会执行父类的该方法。

ChannelHandlerAdapter.(ChannelHandlerContext ctx)

public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    // NOOP
}

没做任何操作, 也就是如果我们没有重写该方法时, 如果添加handler之后将不会做任何操作, 这里如果我们需要做一些业务逻辑, 可以通过重写该方法进行实现

删除

删除的逻辑和添加的逻辑相同,区别删除是将pipeline的双向链表的节点去掉。这里就不详细的分析。

以上就是netty中pipelinehandler添加删除分析的详细内容,更多关于netty pipeline handler的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

netty中pipeline的handler添加删除分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

netty中pipeline的handler添加删除分析

这篇文章主要为大家介绍了netty中pipeline的handler添加删除分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-17

netty pipeline中的inbound和outbound事件传播分析

这篇文章主要为大家介绍了netty pipeline中的inbound和outbound事件传播分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-17

Centos7中添加、删除Swap交换分区的方法

Swap介绍: linux 将物理内存分为内存段,叫做页面。交换是指内存页面被复制到预先设定好的硬盘空间(叫做交换空间)的过程,目的是释放对于页面的内存。物理内存和交换空间的总大小是可用的虚拟内存的总量http://www.cppcns.c
2022-06-04

Linux系统中添加删除分区命令是什么

小编给大家分享一下Linux系统中添加删除分区命令是什么,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!在Linux系统中如果要添加删除分区可以使用fdisk命令,执行命令之后系统会有提示,只需要根据系统提示一步一步的操作。
2023-06-28

Android实现EditText中添加和删除bitmap的方法

本文实例讲述了Android实现EditText中添加和删除bitmap的方法。分享给大家供大家参考,具体如下:SpannableString mSpan1 = new SpannableString("1"); /* * this is
2022-06-06

如何添加或删除PDF文件中的水印

这篇文章将为大家详细讲解有关如何添加或删除PDF文件中的水印,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、怎样添加水印步骤一:在电脑中找到并打开我们需要使用的迅捷PDF编辑器,进入软件后把需要添加水印
2023-06-05

laravel中软删除的实例分析

这篇文章主要介绍“laravel中软删除的实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“laravel中软删除的实例分析”文章能帮助大家解决问题。在laravel中,软删除指的是数据表记录并
2023-06-29

vbs读写注册表之系统启动项添加与删除的示例分析

这篇文章主要介绍了vbs读写注册表之系统启动项添加与删除的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。核心vbs代码变量定义Dim writeName,writeV
2023-06-08

通过Java实现添加或删除PDF中的附件

当我们在制作PDF文件或者PPT演示文稿的时候,为了让自己的文件更全面详细,就会在文件中添加附件。本文为大家整理了Java实现添加或删除PDF中的附件的方法,需要的可以参考下
2023-01-31

添加删除WordPress后台管理菜单分隔符的方法

这篇文章将为大家详细讲解有关添加删除WordPress后台管理菜单分隔符的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。添加删除WordPress后台管理菜单分隔符不知道大家有没有注意过WordPre
2023-06-14

dos或cmd中删除、添加、修改注册表的命令

本篇内容介绍了“dos或cmd中删除、添加、修改注册表的命令”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!regedit的运行参数 REGE
2023-06-08

Linux中删除软连接的示例分析

小编今天带大家了解Linux中删除软连接的示例分析,文中知识点介绍的非常详细。觉得有帮助的朋友可以跟着小编一起浏览文章的内容,希望能够帮助更多想解决这个问题的朋友找到问题的答案,下面跟着小编一起深入学习“Linux中删除软连接的示例分析”的
2023-06-28

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录