Netty的Handler链调用机制及如何组织详解

 更新时间:2023年03月28日 08:38:34   作者:WARRIOR30  
这篇文章主要为大家介绍了Netty的Handler链调用机制及如何组织示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

什么是 Handler

Netty是一款基于NIO的异步事件驱动网络应用框架,其核心概念之一就是Handler。而Handler是Netty中处理事件的核心组件,用于处理入站和出站的数据流,实现业务逻辑和网络协议的处理。

在Netty中,Handler是一个接口,主要分为两种:ChannelInboundHandler(入站Handler)和ChannelOutBoundHandler(出站Handler),如下图所示。

  • ChannelInboundHandler :处理从网络通道中读取到的数据,包括解码、反序列化、消息分发等操作;
  • ChannelOutboundHandler:可以负责将处理结果编码、加密并通过网络通道发送出去等

Handler 是怎么被组织起来的

  • 为了方便事件在各个Handler中处理与传递,在Netty中,每一个ChannelHandler被封装为一个ChannelHandlerContext
  • ChannelHandlerContext提供了对ChannelHandler的访问,以及它前后相邻的ChannelHandler的访问。在ChannelHandlerContext的抽象实现类AbstractChannelHandlerContext,可以很清楚的看到,它拥有nextprev两个属性,分别对应下一个和上一个ChannelHandlerContext
  • 在Netty中,一个完整的处理链路可以由多个ChannelHandlerContext组成,这些ChannelHandlerContext形成一个管道(Pipeline) ,通过管道串联起来,形成完整的数据处理流程。在数据流经过管道中的每个ChannelHandlerContext时,都可以对数据进行一些特定的处理。

Handler 链调用机制

简述

ChannelPipeline的源码中,我们可以看到这样的一段注释

这可能容易让人产生认为Pipeline 中维护了两条链表,其中一条用于处理出站事件,另外一条处理入站事件。

实际上,Pipeline是维护了一条双向链表,当数据从入站方向流经处理程序链时,数据从双向链表的head 向后面遍历,依次将事件交由后面一个handler处理,当数据从出站方向流经处理程序链时,数据从双向链表的tail 向前面遍历,依次将事件交由下一个handler处理。

ChannelPipeline 如何调度 handler

上面提到,Pipeline 中维护了一个由handler双向链表。那么,当事件进入pipeline 中时,ChannelPipeline 是如何调用这些 handler 的呢 ?

  • 当一个请求进入时,pipeline 会首先调用 ChannelContextfireXXX() 方法(下面以 fireChannelRead() 为例),在 fireChannelRead()中,会调用 invokeChannelRead(head, msg) 并将包装着下一个要执行的 handlerChannelContext传入

事件第一个经过的一定是 head ,因此在下面的代码中,invokeChannelRead()传入的是 head

 @Override
 public final ChannelPipeline fireChannelRead(Object msg) {
     AbstractChannelHandlerContext.invokeChannelRead(head, msg);
     return this;
 }
  • 进入invokeChannelRead(),后会调用handler真正的channelRead(this, msg)方法进行业务处理
 private void invokeChannelRead(Object msg) {
     if (invokeHandler()) {
         try {
             ((ChannelInboundHandler) handler()).channelRead(this, msg);
         } catch (Throwable t) {
             notifyHandlerException(t);
         }
     } else {
         fireChannelRead(msg);
     }
 }
  • 进行业务处理之后,channelRead()会执行ctx.fireChannelRead(msg),通过这行代码将处理过的消息传递给下一个处理器进行处理
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
     ctx.fireChannelRead(msg);
 }
  • 从下面的代码可以看到,fireChannelRead() 方法与上面 1 中唯一不同的是,调用了findContextInbound()方法来寻找下一个 handler
  • findContextInbound()中,我们可以发现,它使用了一个 do while 循环来寻找下一个 handler,这个循环当下一个 handler 的类型同为 inbound时,会被返回。因此,当事件入站时,每次进行事件处理的handler 都是 ChannelInboundHandler。(出站同理)
  • 至此,fireChannelRead()调用当前AbstractChannelHandlerContextinvokeChannelRead() 回到 2
 @Override 
 public ChannelHandlerContext fireChannelRead(final Object msg) {
     invokeChannelRead(findContextInbound(), msg);
     return this;
 }
 ​
 private AbstractChannelHandlerContext findContextInbound() {
     AbstractChannelHandlerContext ctx = this;
     do {
         ctx = ctx.next;
     } while (!ctx.inbound);
     return ctx;
 }

从这点可以看出:一般情况下,我们需要在处理程序链中的每个handler调用 ctx.fireChannelRead(msg),以确保将事件传递给下一个处理程序。如果在handler中未调用 ctx.fireChannelRead(msg),则该事件将被截获并停留在当前handler中,不会传递到下一个处理程序。

事件出站的调度从双向链表的tail开始,调用机制与入站类似,这里不再赘述。

以上就是Netty的Handler链调用机制及如何组织详解的详细内容,更多关于Netty Handler链调用的资料请关注脚本之家其它相关文章!

相关文章

  • IDEA集成JProfiler的图文详解

    IDEA集成JProfiler的图文详解

    本文详细介绍了JProfiler的下载、安装和使用过程,首先需要在官网下载对应操作系统的安装包并进行安装,然后填写个人信息进行注册并获取许可证密钥,感兴趣的朋友一起看看吧
    2024-10-10
  • java启动jar包修改JVM默认内存问题

    java启动jar包修改JVM默认内存问题

    这篇文章主要介绍了java启动jar包修改JVM默认内存问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • 5分钟快速学会spring boot整合JdbcTemplate的方法

    5分钟快速学会spring boot整合JdbcTemplate的方法

    这篇文章主要给大家介绍了如何通过5分钟快速学会spring boot整合JdbcTemplate的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot整合JdbcTemplate具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-12-12
  • Java中使用注解获取和改变Bean的指定变量值

    Java中使用注解获取和改变Bean的指定变量值

    Java有时需要通过自定义注解,获取某Bean的某变量的值,根据业务要求处理数据,然后再把新值设置回Bean的同一变量中,这篇文章介绍了使用注解获取和改变Bean变量值的过程,感兴趣想要详细了解可以参考下文
    2023-05-05
  • 由浅入深快速掌握Java 数组的使用

    由浅入深快速掌握Java 数组的使用

    Java 数组 数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。 Java 语言中提供的数组是用来存储固定大小的同类型元素
    2022-04-04
  • Netty启动流程服务端channel初始化源码分析

    Netty启动流程服务端channel初始化源码分析

    这篇文章主要为大家介绍了Netty启动流程服务端channel初始化源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • 浅析JAVA常用JDBC连接数据库的方法总结

    浅析JAVA常用JDBC连接数据库的方法总结

    本篇文章是对在JAVA中常用JDBC连接数据库的方法进行了详细的总结分析,需要的朋友参考下
    2013-07-07
  • IDEA使用GsonFormat完成JSON和JavaBean之间的转换

    IDEA使用GsonFormat完成JSON和JavaBean之间的转换

    这篇文章主要介绍了IDEA使用GsonFormat完成JSON和JavaBean之间的转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Java Stream函数式编程管道流结果处理

    Java Stream函数式编程管道流结果处理

    这篇文章主要为大家介绍了Java Stream函数式编程管道流结果处理的示例过程解析需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Java中System.setProperty()用法与实际应用场景

    Java中System.setProperty()用法与实际应用场景

    System.setProperty是Java中用于设置系统属性的方法,它允许我们在运行时为Java虚拟机(JVM)或应用程序设置一些全局的系统属性,下面这篇文章主要给大家介绍了关于Java中System.setProperty()用法与实际应用场景的相关资料,需要的朋友可以参考下
    2024-04-04

最新评论