千家信息网

Netty分布式pipeline管道异常传播事件的示例分析

发表于:2025-02-09 作者:千家信息网编辑
千家信息网最后更新 2025年02月09日,这篇文章主要介绍了Netty分布式pipeline管道异常传播事件的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。传播异常事件
千家信息网最后更新 2025年02月09日Netty分布式pipeline管道异常传播事件的示例分析

这篇文章主要介绍了Netty分布式pipeline管道异常传播事件的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

传播异常事件

简单的异常处理的场景

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {    throw new Exception("throw Exception");}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    System.out.println(cause.getMessage());}

我们在handler的channelRead方法中主动抛出异常, 模拟程序中出现异常的场景, 经测试会发现, 程序最终会走到exceptionCaught方法中, 获取异常对象并打印其信息

那么抛出异常之后, 是如何走到exceptionCaught方法的呢?

我们回顾之前小节channelRead事件的传播流程, channelRead方法是在AbstractChannelHandlerContext类的invokeChannelRead方法中被调用

我们跟到invokeChannelRead这个方法
private void invokeChannelRead(Object msg) {    if (invokeHandler()) {        try {            //调用了当前handler的channelRead方法, 其实就是head对象调用自身的channelRead方法            ((ChannelInboundHandler) handler()).channelRead(this, msg);        } catch (Throwable t) {            //发生异常的时候在这里捕获异常            notifyHandlerException(t);        }    } else {        fireChannelRead(msg);    }}

这里不难看出, 当调用户自定义的handler的channelRead方法发生异常之后, 会被捕获, 并调用notifyHandlerException方法, 并传入异常对象, 也就是我们示例中抛出的异常

我们跟到fireChannelRead方法中:

private void notifyHandlerException(Throwable cause) {    //代码省略    invokeExceptionCaught(cause);}

再继续跟到invokeExceptionCaught方法中:

private void invokeExceptionCaught(final Throwable cause) {    if (invokeHandler()) {        try {            //当前handler调用exceptionCaught()方法            handler().exceptionCaught(this, cause);        } catch (Throwable error) {            //代码省略        }    } else {        fireExceptionCaught(cause);    }}

走到这里一切都明白了, 这里调用了当前handler的exceptionCaught方法, 也就是我们重写的exceptionCaught方法

知道了为什么会走到exceptionCaught方法之后, 我们再进行剖析异常事件的传播流程

我还是通过两种写法来进行剖析

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    System.out.println(cause.getMessage());}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    //写法1    ctx.fireChannelRead(cause);    //写法2    ctx.pipeline().fireExceptionCaught(cause);}

这两种写法我们并不陌生, 可能我们能直接猜到, 第一种写法是从当前节点进行传播, 第二种写法则从头结点或者尾节点进行转播, 那么和传播inbound事件或outbound事件有什么区别呢?我们先以第二种写法为例, 剖析异常事件传输的整个流程

跟到DefualtChannelPipeline的fireExceptionCaught方法中:

public final ChannelPipeline fireExceptionCaught(Throwable cause) {    AbstractChannelHandlerContext.invokeExceptionCaught(head, cause);    return this;}

我们看到invokeExceptionCaught传入了head节点, 我们可以猜测, 异常事件的传播是从head节点开始的

跟进invokeExceptionCaught方法
static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) {    ObjectUtil.checkNotNull(cause, "cause");    EventExecutor executor = next.executor();    if (executor.inEventLoop()) {        //执行下一个节点的异常方法        next.invokeExceptionCaught(cause);    } else {        try {            executor.execute(new Runnable() {                @Override                public void run() {                    next.invokeExceptionCaught(cause);                }            });        } catch (Throwable t) {            //忽略代码        }    }}

因为这里是传入的是head节点, 所以这里的next指向head节点

我们跟到invokeExceptionCaught方法中, 这里其实是headContext的父类AbstractChannelHandlerContext中的方法:

private void invokeExceptionCaught(final Throwable cause) {    if (invokeHandler()) {        try {            //当前handler调用exceptionCaught()方法            handler().exceptionCaught(this, cause);        } catch (Throwable error) {            //代码省略        }    } else {        fireExceptionCaught(cause);    }}

这里又是我们熟悉的逻辑, 调用当前handler的exceptionCaught方法, 因为当前handler是head, 所以首先会调用headContext的exceptionCaught方法

跟进exceptionCaught方法:

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    ctx.fireExceptionCaught(cause);}

这里仅仅是继续传播异常事件, 这时候我们发现, 这个写法和我们刚才提到传播异常事件的两种写法的第一种写法一样:

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    //写法1    ctx.fireChannelRead(cause);    //写法2    ctx.pipeline().fireExceptionCaught(cause);}

根据我们之前的学习, 我们知道第一种写法是从当前节点传播, 而第二种写法是从头传播, 并且要求传播事件一定要使用第一种写法, 否则事件到这里会重新从头传播进而引发不可预知错误, 这个结论在异常传播同样适用, 同学们一定要注意这点

我们继续跟fireExceptionCaught方法, 这里会走到AbstractChannelHandlerContex类的fireExceptionCaught方法:

public ChannelHandlerContext fireExceptionCaught(final Throwable cause) {    //传播异常事件的时候, 直接拿了当前节点的下一个节点    invokeExceptionCaught(next, cause);    return this;}

这个时候我们发现, 这里并没有去获取下一个的inbound节点还是outbound节点, 而是直接通过next拿到下一个节点, 这就说明在异常事件传播的过程中是不区分inbound事件还是outbound事件的, 都是直接从head节点按照链表结构往下传播,

跟到invokeExceptionCaught方法中
static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) {    ObjectUtil.checkNotNull(cause, "cause");    EventExecutor executor = next.executor();    if (executor.inEventLoop()) {         next.invokeExceptionCaught(cause);    } else {        try {            executor.execute(new Runnable() {                @Override                public void run() {                    next.invokeExceptionCaught(cause);                }            });        } catch (Throwable t) {            //代码省略        }    }}

这里又是我们熟悉的逻辑, 我们知道invokeExceptionCaught中执行了next的exceptionCaught, 这里的next, 因为我们是从head节点开始剖析的, 所以这里很有可能就是用户自定义的handler, 如果用户没有重写exceptionCaught方法, 则会交给用户handler的父类处理

我们以ChannelInboundHandlerAdapter为例看它的该方法实现:

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)        throws Exception {    ctx.fireExceptionCaught(cause);}

我们看到这里继续向下传播了异常事件

走到这里我们会知道, 如果我们没有重写exceptionCaught方法, 异常事件会一直传播到链表的底部, 就是tail节点

我们跟到TailConext的exceptionCaught方法:

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {    onUnhandledInboundException(cause);}

感谢你能够认真阅读完这篇文章,希望小编分享的"Netty分布式pipeline管道异常传播事件的示例分析"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

方法 传播 事件 节点 写法 代码 用户 篇文章 剖析 示例 对象 就是 时候 流程 还是 分布式 管道 分析 也就是 从头 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 山西诚隆网络技术有限公司 吴中网络安全保卫大队在哪儿 网络安全产品的厂商有哪些 时序数据库市场 大专计算机网络技术难学吗 软件开发工具管理程序下载 网络安全在国家安全中重要性 如何防止网络安全防范措施 从PDB数据库中查找一个蛋白质 wifi宽带营运商服务器未响应 本地iis web服务器 网络安全的英语演讲作文 SQL数据库实例更换磁盘 警察网络安全知识宣传 数据库文档自动生成器 mc服务器注册插件在哪 自定义数据库查重的免费软件 绵阳市公安局网络安全保卫支 服务器远程桌面空白怎么解决 网络安全 做什么 服务器备案在哪个省 威海山东软件开发 zkm服务器的数据库怎么进 比较数据库 数据 北京大数据守时模块服务器 部队清退数据库外职工该怎么赔偿 梦幻转区后原服务器变吗 公安网络安全工作重要性 乐山导航软件开发 网络安全班周会新闻稿
0