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 2.0:Memory
java·后端·spring
码匠许师傅6 小时前
【C++ 面试真题】聊聊 C++ 的移动语义与右值引用
java·c++·面试
小席是个热心肠6 小时前
AI相关的自我学习
java·人工智能·学习
波波0077 小时前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
数智化管理手记9 小时前
海量数据如何沉淀有效数据资产?数据标准化治理方案如何搭建?
java·大数据·人工智能
隔窗听雨眠9 小时前
GBase 8s并发控制深度解析:封锁机制、隔离级别与死锁处理全攻略
服务器·数据库·oracle
cfm_29149 小时前
SpringAI + Ollama 本地大模型
java·开发语言·人工智能·语言模型
鲸采云SRM采购管理系统10 小时前
采购管理系统哪家好?2026最新测评对比
java·服务器·数据库
那年窗外下的雪.11 小时前
AIDC 学习日志 第 04 天 BGP Underlay 基础与路由选择
服务器·学习·php
0x5311 小时前
Java网络编程(二)
java·服务器·网络