Netty 学习(四)服务编排层

一、前言

EventLoop 是 Netty 的调度中心,负责监听多种事件类型:I/O 事件、信号事件、定时事件等,而实际的业务处理逻辑则是由 ChannelPipeline 中所定义的 ChannelHandler 完成的。Netty 服务编排层的核心组件 ChannelPipeline 和 ChannelHandler 为用户提供了 I/O 事件的全部控制权。


二、ChannelPipeline 概述

Pipeline 的字面意思是管道、流水线。在 Netty 中 ChannelPipeline 起到的作用可以近似的理解为工厂流水线:原始的网络字节经过 Pipeline,被一步步加工包装,最后得到加工后的产品。

这样我们便对 ChannelPipeline 有一个初步印象:它是 Netty 的核心处理链,用以实现网络事件的动态编排和有序传播。

1. ChannelPipeline 内部结构

1.1 内部结构

在这里插入图片描述

  1. 每个 Channel 会绑定一个 ChannelPipeline, 每个 ChannelPipeline 都包含多个 ChannelHandlerContext。ChannelPipeline 中所有的 ChannelHandlerContext 通过双向链表链接在一起。
  2. ChannelHandlerContext 用于保存 ChannelHandler 上下文,包含生命周期的所有事件,如 connect、bind、read、flush、write、close 等。
  3. ChannelHandler 负责实际的数据加工和处理,每个 ChannelHandler 都对应一个 ChannelHandlerContext。当有 I/O 事件触发时, ChannelPipeline 会依次调用 ChannelHandler 对 Channel 的数据进行拦截和处理。

1.2 ChannelPipeline 双向链表的构造

ChannelPipeline 的双向链表分别维护了 HeadContext 和 TailContext 的头尾节点。我们自定义的 ChannelHandler 会插入到 Head 和 Tail 之间,这两个节点在 Netty 中已经默认实现了。
在这里插入图片描述

HeadContext

HeadContext 既是 Inbound 处理器,也是 Outbound 处理器。它分别实现了 ChannelInboundHandler 和 ChannelOutboundHandler。网络数据写入操作的入口就是由 HeadContext 节点完成的。HeadContext 作为 Pipeline 的头结点负责读取数据并开始传递 InBound 事件,当数据处理完成后,数据会反方向经过 Outbound 处理器,最终传递到 HeadContext,所以 HeadContext 又是处理 Outbound 事件的最后一站。此外 HeadContext 在传递事件之前,还会执行一些前置操作。

TailContext

TailContext 只实现了 ChannelInboundHandler 接口。它会在 ChannelInboundHandler 调用链路的最后一步执行,主要用于终止 Inbound 事件传播,例如释放 Message 数据资源等。TailContext 节点作为 OutBound 事件传播的第一站,仅仅是将 OutBound 事件传递给上一个节点。

1.3 入站与出站

在这里插入图片描述根据网络数据的流向,ChannelHandler 分为入站 ChannelInboundHandler 和出站 ChannelOutboundHandler 两种处理器。在客户端与服务端通信的过程中,数据从客户端进入服务端的过程叫入站,反之称为出站。数据先由一系列 InboundHandler 处理后入站,然后再由相反方向的 OutboundHandler 处理完成后出站。

2. ChannelHandler 接口设计

ChannelHandler 有两个重要的子接口:ChannelInboundHandler和ChannelOutboundHandler,分别拦截入站和出站的各种 I/O 事件。

2.1 ChannelInboundHandler 的事件回调方法与触发时机

事件回调方法触发时机
channelRegisteredChannel 被注册到 EventLoop
channelUnregisteredChannel 从 EventLoop 中取消注册
channelActiveChannel 处于就绪状态,可以被读写
channelInactiveChannel 处于非就绪状态Channel 可以从远端读取到数据
channelReadChannel可以从远端读取到数据
channelReadCompleteChannel 读取数据完成
userEventTriggered用户事件触发时
channelWritabilityChangedChannel 的写状态发生变化

2.2 ChannelOutboundHandler 的事件回调方法与触发时机

直接通过 ChannelOutboundHandler 的接口列表可以看到每种操作所对应的回调方法,如下图所示。
在这里插入图片描述

3. ChannelPipeline 事件传播机制

ChannelPipeline 可分为入站 ChannelInboundHandler 和出站 ChannelOutboundHandler 两种处理器,与此对应传输的事件类型可以分为Inbound 事件和 Outbound 事件。
Inbound 事件和 Outbound 事件的传播方向是不一样的,Inbound 事件的传播方向为 Head -> tail, 而 Outbound 事件的传播方向是 Tail -> Head。

4. ChannelPipeline 异常传播机制

ChannelPipeline 事件传播的实现采用了经典的责任链模式,调用链路环环相扣。如果有一个节点处理逻辑发生异常,可以通过 exceptionCaught 方法进行捕获,通过 ctx.fireExceptionCaugh 方法可以将异常按顺序传播到 Tail 节点。如果用户没有对异常进行拦截处理,最后将由 Tail 节点统一处理。

	protected void onUnhandledInboundException(Throwable cause) {
	    try {
	        logger.warn(
	                "An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " +
	                        "It usually means the last handler in the pipeline did not handle the exception.",
	                cause);
	    } finally {
	        ReferenceCountUtil.release(cause);
	    }
	}

异常的统一拦截处理

在 ChannelPipeline 自定义处理器的末端添加统一的异常处理器,这也是 Netty 推荐的最佳异常处理实践。此时 ChannelPipeline 的内部结构如下图所示。
在这里插入图片描述

    public class ExceptionHandler extends ChannelDuplexHandler {
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            if (cause instanceof RuntimeException) {
                System.out.println("Handle Business Exception Success.");
            }
        }
    }

三、总结

关于 Netty 的服务编排,主要是通过 ChannelPipeline 管理的 ChannelHandler 链表来实现:

  1. ChannelHandlerContext 是对 ChannelHandler 的封装,每个 ChannelHandler 都对应一个 ChannelHandlerContext,实际上 ChannelPipeline 维护的是与 ChannelHandlerContext 的关系。

  2. I/O 事件和 Channel 数据在 ChannelHandler 链中传播, Inbound 事件和 Outbound 事件的传播方向相反,Inbound 事件的传播方向为 Head -> Tail,而 Outbound 事件传播方向是 Tail -> Head。

  3. 异常事件的传播顺序与 ChannelHandler 的添加顺序相同,会依次向后传播,与 Inbound 事件和 Outbound 事件无关。exceptionCaught 捕获异常, 通过在自定义处理器的末端添加统一的异常处理器优雅的处理异常。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值