Netty异常传播机制

java 复制代码
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
        throws Exception {
    ctx.fireExceptionCaught(cause);
}

调用ctx.fireExceptionCaught(cause); 来进行异常的向下传播,ctx是ChannelHandlerContext。因为pipeline中的每个节点是以ChannelHandlerContext形式构成的双向链表。

AbstractChannelHandlerContext 是顶级抽象,每个ChannelHandlerContext内部都持有一个指针指向下一个节点和上一个节点。

java 复制代码
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap
        implements ChannelHandlerContext, ResourceLeakHint {
    volatile AbstractChannelHandlerContext next;
    volatile AbstractChannelHandlerContext prev;
    }

ctx.fireExceptionCaught(cause);这个方法在把异常向下传播。这个方法显然需要定义在抽象类AbstractChannelHandlerContext中。因为每一个节点都有权利来决定是否向下传播,现在这个设计定义在父级抽象类中更合适。

父类中定义了如下代码:

java 复制代码
@Override
public ChannelHandlerContext fireExceptionCaught(final Throwable cause) {
   invokeExceptionCaught(next, cause);
   return this;
}

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) {
           if (logger.isWarnEnabled()) {
               logger.warn("Failed to submit an exceptionCaught() event.", t);
               logger.warn("The exceptionCaught() event that was failed to submit was:", cause);
           }
       }
   }
}

上面的代码看出,实际调用是父级的静态抽象方法:

static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) 这个方法接收两个参数 第一个 就是:下一个要传播的节点next, 第二个就是:传播的异常。显然next的取值来自于双向链表的下一个指针。也就是最上面的volatile AbstractChannelHandlerContext next;

最终都会调用到:每一个节点的invokeExceptionCaught

invokeExceptionCaught也是定义在抽象类中的,并且是private方法。

java 复制代码
private void invokeExceptionCaught(final Throwable cause) {
    if (invokeHandler()) {
        try {
            handler().exceptionCaught(this, cause);
        } catch (Throwable error) {
            if (logger.isDebugEnabled()) {
                logger.debug(
                    "An exception {}" +
                    "was thrown by a user handler's exceptionCaught() " +
                    "method while handling the following exception:",
                    ThrowableUtil.stackTraceToString(error), cause);
            } else if (logger.isWarnEnabled()) {
                logger.warn(
                    "An exception '{}' [enable DEBUG level for full stacktrace] " +
                    "was thrown by a user handler's exceptionCaught() " +
                    "method while handling the following exception:", error, cause);
            }
        }
    } else {
        fireExceptionCaught(cause);
    }
}

整个这个private中的逻辑 invokeHandler()是先检查是否handler被移除了,是否还有效,如果有效就调用handler的handler().exceptionCaught(this, cause)

权限收口: 将核心执行逻辑设为 private,是为了防止子类破坏"检查-执行-保护"的固定流水线流程。

抽象类处理通用的框架逻辑,不让用户自己私自修改,防止流程上被破坏,只是给用户留了handler中的exceptionCaught用来决定怎么处理异常。

异常的传播,牢牢的掌握在AbstractChannelHandlerContext这个类中。AbstractChannelHandlerContext负责整个流程的契约。防止 "子类破坏了父类的契约"

总结

1.异常从pipeline中的当前节点,一直向后传播,一直到tail节点。不区分inboundHandler还是outboundHandler

2.如果handler不重写 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception

ChannelInboundHandlerAdapter的默认实现就是直接向下传播。

java 复制代码
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
        throws Exception {
    ctx.fireExceptionCaught(cause);
}

3.整个流程都封装在抽象类中了,防止开发者破坏整个pipeline的流转流程

相关推荐
砍材农夫6 分钟前
spring-ai 第四多模态API
java·人工智能·spring
她说..3 小时前
Java 对象相关高频面试题
java·开发语言·spring·java-ee
Boop_wu3 小时前
[Java 算法] 字符串
linux·运维·服务器·数据结构·算法·leetcode
庞轩px3 小时前
深入理解 sleep() 与 wait():从基础到监视器队列
java·开发语言·线程··wait·sleep·监视器
m0_694845574 小时前
Dify部署教程:从AI原型到生产系统的一站式方案
服务器·人工智能·python·数据分析·开源
皮皮林5514 小时前
面试官:ZSet 的底层实现是什么?
java
码云数智-大飞4 小时前
C++ RAII机制:资源管理的“自动化”哲学
java·服务器·php
2601_949816584 小时前
Spring+Quartz实现定时任务的配置方法
java
SkyXZ~5 小时前
Jetson有Jtop,Linux有Htop,RDK也有Dtop!
linux·运维·服务器·rdkx5·rdks100·dtop
计算机毕设指导65 小时前
基于SpringBoot校园学生健康监测管理系统【源码文末联系】
java·spring boot·后端·spring·tomcat·maven·intellij-idea