当前位置: 首页 > news >正文

Dubbo捕获自定义异常

一.问题描述

Dubbo远程服务提供者抛出的自定义异常无法被消费方正常捕获,消费方捕获的自定义异常全部变成RuntimeException,使用起来很不方便。

二.原因分析

相关源码

/** Licensed to the Apache Software Foundation (ASF) under one or more* contributor license agreements.  See the NOTICE file distributed with* this work for additional information regarding copyright ownership.* The ASF licenses this file to You under the Apache License, Version 2.0* (the "License"); you may not use this file except in compliance with* the License.  You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
package org.apache.dubbo.rpc.filter;import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.service.GenericService;
import org.apache.dubbo.rpc.support.RpcUtils;import java.lang.reflect.Method;import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FILTER_VALIDATION_EXCEPTION;/*** ExceptionInvokerFilter* <p>* Functions:* <ol>* <li>unexpected exception will be logged in ERROR level on provider side. Unexpected exception are unchecked* exception not declared on the interface</li>* <li>Wrap the exception not introduced in API package into RuntimeException. Framework will serialize the outer exception but stringnize its cause in order to avoid of possible serialization problem on client side</li>* </ol>*/
@Activate(group = CommonConstants.PROVIDER)
public class ExceptionFilter implements Filter, Filter.Listener {private ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ExceptionFilter.class);@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {return invoker.invoke(invocation);}@Overridepublic void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {try {Throwable exception = appResponse.getException();// directly throw if it's checked exceptionif (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {return;}// directly throw if the exception appears in the signaturetry {Method method = invoker.getInterface().getMethod(RpcUtils.getMethodName(invocation), invocation.getParameterTypes());Class<?>[] exceptionClasses = method.getExceptionTypes();for (Class<?> exceptionClass : exceptionClasses) {if (exception.getClass().equals(exceptionClass)) {return;}}} catch (NoSuchMethodException e) {return;}// for the exception not found in method's signature, print ERROR message in server's log.logger.error(CONFIG_FILTER_VALIDATION_EXCEPTION, "", "","Got unchecked and undeclared exception which called by " + RpcContext.getServiceContext().getRemoteHost() +". service: " + invoker.getInterface().getName() + ", method: " + RpcUtils.getMethodName(invocation) +", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);// directly throw if exception class and interface class are in the same jar file.String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {return;}// directly throw if it's JDK exceptionString className = exception.getClass().getName();if (className.startsWith("java.") || className.startsWith("javax.") || className.startsWith("jakarta.")) {return;}// directly throw if it's dubbo exceptionif (exception instanceof RpcException) {return;}//   这里把其它情况的异常都改为RuntimeException抛出// otherwise, wrap with RuntimeException and throw back to the clientappResponse.setException(new RuntimeException(StringUtils.toString(exception)));} catch (Throwable e) {logger.warn(CONFIG_FILTER_VALIDATION_EXCEPTION, "", "","Fail to ExceptionFilter when called by " + RpcContext.getServiceContext().getRemoteHost() +". service: " + invoker.getInterface().getName() + ", method: " + RpcUtils.getMethodName(invocation) +", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);}}}@Overridepublic void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {logger.error(CONFIG_FILTER_VALIDATION_EXCEPTION, "", "","Got unchecked and undeclared exception which called by " + RpcContext.getServiceContext().getRemoteHost() +". service: " + invoker.getInterface().getName() + ", method: " + RpcUtils.getMethodName(invocation) +", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);}// For test purposepublic void setLogger(ErrorTypeAwareLogger logger) {this.logger = logger;}
}

源码中只有以下几种情况会直接抛出异常

1. 非RuntimeException,直接抛出异常
2. 如果是checked异常,直接抛出
3. 在方法签名上有声明,直接抛出
4. 异常类和接口类在同一个jar包,直接抛出
5. 是JDK自带的包名以java、javax、jakarta开头的异常,直接抛出
6. 是dubbo本身的RpcException异常,直接抛出

这样的话那最简单的方案就是重写ExceptionFilter,在识别到我们程序自定义异常时也return就可以在消费端正常捕获并处理异常

三.解决方法

1.重写ExceptionFilter的onResponse方法

public class DubboExceptionFilter extends ExceptionFilter {private ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ExceptionFilter.class);/**redis校验异常 字符串*/private static final String REDIS_VALID_EXCEPTION_TEXT = "RedisValidException";@Overridepublic void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {if(!appResponse.hasException() || GenericService.class == invoker.getInterface()) {return;}try {Throwable exception = appResponse.getException();// directly throw if it's checked exceptionif (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {return;}/*--------------------------------------自定义的异常处理--------------------------------------------*/if(exception instanceof BusinessFailException) {return;}//如果还有其它需要直接抛出的异常,也在这里处理/*--------------------------------------自定义的异常处理--------------------------------------------*/// directly throw if the exception appears in the signaturetry {Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());Class<?>[] exceptionClasses = method.getExceptionTypes();for (Class<?> exceptionClass : exceptionClasses) {if (exception.getClass().equals(exceptionClass)) {return;}}} catch (NoSuchMethodException e) {return;}// for the exception not found in method's signature, print ERROR message in server's log.logger.error(CONFIG_FILTER_VALIDATION_EXCEPTION, "", "", "Got unchecked and undeclared exception which called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);// directly throw if exception class and interface class are in the same jar file.String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {return;}// directly throw if it's JDK exceptionString className = exception.getClass().getName();if (className.startsWith("java.") || className.startsWith("javax.")) {return;}// directly throw if it's dubbo exceptionif (exception instanceof RpcException) {return;}// 除了以上所有的异常,其它异常都改为RuntimeException抛出appResponse.setException(new RuntimeException(StringUtils.toString(exception)));} catch (Throwable e) {logger.warn(CONFIG_FILTER_VALIDATION_EXCEPTION, "", "", "Fail to ExceptionFilter when called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);}}
}

2.配置让自定义Filter生效

在服务提供方resources目录下创建META-INF/dubbo文件夹,在新建的文件夹下创建org.apache.dubbo.rpc.Filter文件,文件内容为

dubboExceptionFilter=你的包名.DubboExceptionFilter

 3.修改配置

以properties配置为例


#自定义的异常捕获filter
dubbo.provider.filter=dubboExceptionFilter,-exception

四.Dubbo版本>= 3.1.6的问题

dubbo 3.1.6以上版本提高了序列化安全检查强度,自定义的异常抛出时会因为安全问题无法序列化

配置文件中加入以下配置可解决

#检查模式级别改为WARN
dubbo.application.serialize-check-status=WARN

 问题参考

 Dubbo新版本(>3.2)序列化问题

相关文章:

Dubbo捕获自定义异常

一.问题描述 Dubbo远程服务提供者抛出的自定义异常无法被消费方正常捕获&#xff0c;消费方捕获的自定义异常全部变成RuntimeException&#xff0c;使用起来很不方便。 二.原因分析 相关源码 /** Licensed to the Apache Software Foundation (ASF) under one or more* con…...

Leetcode刷题详解——求根节点到叶节点数字之和

1. 题目链接&#xff1a;129. 求根节点到叶节点数字之和 2. 题目描述&#xff1a; 给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&#xff1a; 例如&#xff0c;从根节点到叶节点的路径 1…...

emq集群配置nginx做负载均衡

emq集群配置nginx做负载均衡 创建 EMQ X 节点集群 emqx 集群搭建 例如: 节点IP 地址emqx192.168.1.17192.168.1.17emqx192.168.1.18192.168.1.18emqx192.168.1.19192.168.1.19 配置 /etc/nginx/nginx.conf mqtt集群搭建并使用nginx做负载均衡_亲测得结论 示例: vim /et…...

【JAVA学习笔记】60 - 坦克大战1.0-绘图坐标体系、事件处理机制

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter16/src/com/yinhai 绘图坐标体系 一、基本介绍 下图说明了Java坐标系。坐标原点位于左上角&#xff0c;以像素为单位。在Java坐标系中&#xff0c;第一个是x坐标&#xff0c;表示当前位置为…...

Android13 安装谷歌GMS导致打开蓝牙失败解决方法

Android13 安装谷歌GMS导致打开蓝牙失败解决方法 文章目录 Android13 安装谷歌GMS导致打开蓝牙失败解决方法一、前言二、解决方法1、简单的解决方法2、添加属性和日志解决 三、分析1、查看异常日志2、 查看蓝牙相关日志 四、总结1、Android13 安装谷歌GMS导致打开蓝牙失败具体原…...

独创改进 | RT-DETR 引入双向级联特征融合结构 RepBi-PAN | 附手绘结构图原图

本专栏内容均为博主独家全网首发,未经授权,任何形式的复制、转载、洗稿或传播行为均属违法侵权行为,一经发现将采取法律手段维护合法权益。我们对所有未经授权传播行为保留追究责任的权利。请尊重原创,支持创作者的努力,共同维护网络知识产权。 文章目录 YOLOv6贡献RepBi-…...

Ubuntu下安装vscode,并解决终端打不开vscode的问题

Visual Studio Code安装 1&#xff0c;使用 apt 安装 Visual Studio Code 在官方的微软 Apt 源仓库中可用。按照下面的步骤进行即可&#xff1a; 以 sudo 用户身份运行下面的命令&#xff0c;更新软件包索引&#xff0c;并且安装依赖软件&#xff1a; sudo apt update sud…...

Spring Boot Actuator 漏洞利用

文章目录 前言敏感信息泄露env 泄露配置信息trace 泄露用户请求信息mappings 泄露路由信息heapdump泄露堆栈信息 前言 spring对应两个版本&#xff0c;分别是Spring Boot 2.x和Spring Boot 1.x&#xff0c;因此后面漏洞利用的payload也会有所不同 敏感信息泄露 env 泄露配置信…...

acwing算法基础之数据结构--trie算法

目录 1 基础知识2 模板3 工程化 1 基础知识 trie树算法&#xff0c;也叫作字典树算法。 用处&#xff1a;用来高效存储和查找字符串集合的数据结构。 &#xff08;一&#xff09; 定义变量。 const int N 1e5 10; int son[N][26], cnt[N], idx; char str[N];&#xff08;二…...

ES from+size>10000报错

参考博客 from size > 10000就会报错 Result window is too large, from size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_…...

(04)Mycat实现分库

1、如何选择分库表 #客户表 rows:20万 CREATE TABLE customer(id INT AUTO_INCREMENT,NAME VARCHAR(200),PRIMARY KEY(id) );#订单表 rows:600万 CREATE TABLE orders(id INT AUTO_INCREMENT,order_type INT,customer_id INT,amount DECIMAL(10,2),PRIMARY KEY(id) ); #…...

DeepSORT多目标跟踪——算法流程与源码解析

一、目标检测与目标追踪 1. 目标检测 在目标检测任务中&#xff0c;主要目标是识别图像或视频帧中存在的物体的位置和类别信息。这意味着目标检测算法需要定位物体的边界框&#xff08;Bounding Box&#xff09;并确定每个边界框内的物体属于哪个类别&#xff08;如人、汽车、…...

C++查漏补缺与新标准(C++20,C++17,C++11)02 C++快速回顾(二)

本内容参考C20高级编程 C风格的数组 //形如 int myArray[3]{2};一个比较新颖的获取C风格数组大小的函数std::size()&#xff0c;返回size_t类型&#xff08;在中定义的无符号整数&#xff09; #include <iostream> using namespace std;int main() {int myArray[5] {…...

红米K40功能介绍

红米K40是小米旗下的一款高性能智能手机。以下是红米K40的一些功能介绍及新增功能&#xff1a; 1.高性能处理器&#xff1a;红米K40搭载了骁龙870处理器&#xff0c;提供强大的性能和流畅的操作体验。 2.120Hz刷新率屏幕&#xff1a;红米K40采用了6.67英寸的AMOLED全面屏&…...

壹[1],Opencv常用结构

1&#xff0c;Point类&#xff1a;点表示 point表示二维结构的点,(x,y) cv::Point point; point.x 100; point.y 100; 2&#xff0c;Scalar类&#xff1a;颜色表示 cv::Scalar colorBlue(255,0,0);//蓝色 cv::Scalar colorGreen(0, 255, 0);//绿色 cv::Scalar colorRed(0, …...

Linux常用指令(一)——目录操作

Linux目录操作 1.1 目录切换 cd1.2 目录查看 ls1.3 创建目录 mkdir1.4 删除目录 rm1.5 复制目录 cp1.6 删除目录 rm1.7 搜索目录 find1.8 查看当前所在目录 pwd 更加完整的Linux常用指令 1.1 目录切换 cd # 切换到根目录 cd / # 切换到根目录的usr目录 cd /usr # 返回上一级目…...

前端基础之jQuery

一.什么是jQuery jQuery是一个轻量级的、兼容多浏览器的JavaScript库。jQuery使用户能够更方便地处理HTML Document、Events、实现动画效果、方便地进行Ajax交互&#xff0c;能够极大地简化JavaScript编程。它的宗旨就是&#xff1a;“Write less, do more.“ jQuery内部封装了…...

【基于HTML5的网页设计及应用】——实现个人简历表格和伪类选择器应用

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…...

思考(九十二):DBProxy实现多级存储和事务处理

DBProxy 数据处理的主控室 后端开发一块重要的内容就是如何处理数据。比如: 问题说明统一的访问界面如游戏服只需要 Load、Save、Begin、Commit、Rollback 接口多级存储来降低成本如热数据在 Redis ;冷数据在 MySQL ;长时间非活跃,则归档 OSS同个逻辑涉及多个数据更新要么…...

新手入门Python一定要看的八个超实用建议!

文章目录 前言一、项目文件事先做好归档二、永远不要手动修改源数据并且做好备份三、做好路径的正确配置四、代码必要的地方做好备注与说明五、加速你的Python循环代码六、可视化你的循环代码进度七、使用高效的异常捕获工具八、要多考虑代码健壮性关于Python技术储备一、Pytho…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...