定义dubbo自己的异常过滤器

news2024/11/16 13:41:09

起因
发现这个问题的起因是前端联调接口的时候发现统一的异常处理没有发挥作用,我们定义的处理的异常类型为AppException(国际惯例继承于RuntimeException),但是Dubbo服务端实际返回的异常变成了RuntimeException,我们自定义的异常处理没有发生作用,导致前端报500异常而不是正常的错误提示.

深入研究Dubbo的异常处理
针对发现的问题,查阅了相关的代码和源码发现Dubbo有一个自带的过滤器接口声明了,并且实现了一个异常过滤器,当服务端抛出异常给消费端时异常都会被该异常过滤器处理(其实可以转换思维理解一下,rpc无非就是通过特定的网络协议进行数据传输,既然是网络传输,和我们的接口调用就应该类似,就应该存在一个过滤器之类的东西)
接口类名: com.alibaba.dubbo.rpc.Filter ,
 

异常过滤器代码

/*
 * 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 com.mr.common.filter;

import com.mr.common.exception.BizException;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.logger.Logger;
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 java.lang.reflect.Method;


/**
 * 自定义dubbo异常过滤器
 * 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 DubboExceptionFilter implements Filter, Filter.Listener {
    private Logger logger = LoggerFactory.getLogger(DubboExceptionFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        return invoker.invoke(invocation);
    }

    @Override
    public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
        if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
            try {
                Throwable exception = appResponse.getException();
                //如果是自定义异常,直接返回
                if (exception instanceof BizException) {
                    return;
                }
                // directly throw if it's checked exception
                if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
                    return;
                }
                // directly throw if the exception appears in the signature
                try {
                    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("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 exception
                String className = exception.getClass().getName();
                if (className.startsWith("java.") || className.startsWith("javax.")) {
                    return;
                }
                // directly throw if it's dubbo exception
                if (exception instanceof RpcException) {
                    return;
                }

                // otherwise, wrap with RuntimeException and throw back to the client
                appResponse.setException(new RuntimeException(StringUtils.toString(exception)));
            } catch (Throwable e) {
                logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
            }
        }
    }

    @Override
    public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) {
        logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
    }

    // For test purpose
    public void setLogger(Logger logger) {
        this.logger = logger;
    }
}

上面代码最重要的是这句话:

//如果是自定义异常,直接返回
if (exception instanceof BizException) {
    return;
}

然后在resources目录下创建文件:META-INF/dubbo/org.apache.dubbo.rpc.Filter

 

中间的META-INF目录和dubbo目录也需要自己创建 

文件org.apache.dubbo.rpc.Filter内容为(注意:文件名就叫org.apache.dubbo.rpc.Filter,必须是这样):

dubboExceptionFilter=com.provider.service.filter.DubboExceptionFilter

 

dubboExceptionFilter:随便取,不能和原有的重复,原有的不知道有些啥,取得长一点应该就不会重复

com.provider.service.filter.DubboExceptionFilter:我们刚刚创建的自定义异常过滤器全类名

要把原有的异常过滤器去掉,不然会有两个异常过滤器执行:
在application.yml中添加配置:

dubbo:
  provider:
    #去除dubbo默认异常处理过滤器,改用自己的
    filter: -exception

 这样就搞定了,抛出异常就不会是RuntimeException,而是自己自定义的BizException了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/814836.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

恒运资本:A股、港股全线爆发,沪指突破3300点,恒指重返2万点上方

7月31日&#xff0c;两市股指高开高走&#xff0c;沪指在金融、地产、酿酒等权重板块的带动下一举突破3300点。截至发稿&#xff0c;沪指、深成指、创业板指涨幅均超1%&#xff0c;上证50指数涨近2%。Wind数据显现&#xff0c;北向资金净买入超25亿元。 职业方面&#xff0c;券…

清风徐来【个人】

清风徐来【个人】 前言版权清风徐来【个人】我的博客我的专栏我的粉丝我获得的奖品我的其他平台我的投稿 最后 前言 2023-7-29 10:57:54 花若向阳花自开 人若向暖清风徐来 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是https…

笔记本数据恢复,这5个方法记好了!

我的笔记本从大学就开始用了&#xff0c;里面有很多重要的资料和文件。但昨天打开时&#xff0c;它突然卡着了&#xff0c;等到恢复过来之后&#xff0c;我发现我有些数据就是莫名其妙就消失了。有什么方法能帮我恢复笔记本的数据吗&#xff1f;” 随着笔记本电脑在我们生活中扮…

【LeetCode】不同路劲(动态规划)

不同路劲 题目描述算法流程编程代码 链接: 不同路劲 题目描述 算法流程 编程代码 class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>> dp(m 1,vector<int>(n 1));dp[1][0] 1;for(int i 1;i < m;i){for(int j 1;j < n…

【MySQL】存储过程(十一)

🚗MySQL学习第十一站~ 🚩本文已收录至专栏:MySQL通关路 ❤️文末附全文思维导图,感谢各位点赞收藏支持~ 一.引入 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程可以简化应用开发人员的工作,可以减少数据在数据库和应用服务器之间的传输,…

基于SSM 球鞋资讯交流平台-计算机毕设 附源码11819

SSM 球鞋资讯交流平台 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;球鞋资讯交流平台当然也不能排除在外。球鞋资讯交流平台是以实际运用为开发背景&#xff0c;运用…

Cesium态势标绘专题-钳击箭头(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

HDFS高阶优化方案:短路本地读取,节点负载平衡器

HDFS高阶优化方案 短路本地读取&#xff1a;short circuit local reads背景实现老版本的设计实现安全性改进版设计实现Unix domain socket 配置配置一----libhadoop.so配置二---hdfs-site.xml 节点block负载平衡器&#xff1a;balancer背景命令行配置运行balancer 短路本地读取…

进程创建大盘点

进程创建回顾 通过 fork() 创建子进程&#xff0c;然后通过 execve(...) 将子进程的进程空间替代为 path 所指定程序的进程空间&#xff0c;随后执行 path 所指定的程序 问题 进程创建是否只能依赖于 fork() 和 execve(...) ? 再轮进程创建 fork() 通过完整复制当前进程的方…

金蝶云星空和旺店通·旗舰奇门单据接口对接

金蝶云星空和旺店通旗舰奇门单据接口对接 对接系统&#xff1a;旺店通旗舰奇门 旺店通是北京掌上先机网络科技有限公司旗下品牌&#xff0c;国内的零售云服务提供商&#xff0c;基于云计算SaaS服务模式&#xff0c;以体系化解决方案&#xff0c;助力零售企业数字化智能化管理升…

参数量仅有50KB的超轻量级unet变种网络egeunet【参数和计算量降低494和160倍】医疗图像分割实践

今天看到一篇挺有意思的文章&#xff0c;做的是跟医疗图像分割相关的工作&#xff0c;但是不像之前看到的一些工作一味地去追求高精度&#xff0c;因为医疗领域本身就是一个相对特殊的行业&#xff0c;对于模型产生的结果的精确性要求是很高的&#xff0c;带来的是参数量级的庞…

Pytorch深度学习-----神经网络之卷积层用法详解

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

交通运输安全大数据分析解决方案

当前运输市场竞争激烈&#xff0c;道路运输企业受传统经营观念影响&#xff0c;企业管理者安全意识淡薄&#xff0c;从业人员规范化、流程化的管理水平较低&#xff0c;导致制度规范在落实过程中未能有效监督与管理&#xff0c;执行过程中出现较严重的偏差&#xff0c;其营运车…

【C++入门到精通】C++入门 —— 类和对象(初始化列表、Static成员、友元、内部类、匿名对象)

目录 一、初始化列表 ⭕初始化列表概念 ⭕初始化列表的优点 ⭕使用场景 ⭕explicit关键字 二、Static成员 ⭕Static成员概念 &#x1f534;静态数据成员&#xff1a; &#x1f534;静态函数成员&#xff1a; ⭕使用静态成员的优点 ⭕使用静态成员的注意事项 三、友…

国际化警告Fall back to translate ‘creator‘ key with ‘zn‘ locale.

发现是自己粗心写错了一个单词 这个需要改成zh

OC对象内存布局与isa指针

文章目录 一、Objective-C的本质二、一个objc对象如何进行内存布局&#xff1f;考虑父类的情况三、一个objc对象的isa指针指向什么&#xff1f;有什么作用四、objc对象的类方法和实例方法有什么本质区别和联系&#xff1f; 一、Objective-C的本质 Objc的底层实现是C\C代码&…

微信小程序tab加列表demo

一、效果 代码复制即可使用&#xff0c;记得把图标替换成个人工程项目图片。 微信小程序开发经常会遇到各种各样的页面组合&#xff0c;本demo为list列表与tab组合&#xff0c;代码如下&#xff1a; 二、json代码 {"usingComponents": {},"navigationStyle&q…

goctl template一定制化服务配置生成

官网介绍&#xff1a; 模板&#xff08;Template&#xff09;是数据驱动生成的基础&#xff0c;所有的代码&#xff08;rest api、rpc、model、docker、kube&#xff09;生成都会依赖模板&#xff0c; 默认情况下&#xff0c;模板生成器会选择内存中的模板进行生成&#xff0c…

easyui实用点

easyui实用点 1.下拉框&#xff08;input框只能选不能手动输入编辑&#xff09; data-options"editable:false"//不可编辑2.日期框&#xff0c;下拉框&#xff0c;文本框等class class"easyui-datebox"//不带时分秒 class"easyui-datetimebox"…

口碑+丨香港邮政联合极智嘉建立全港首个机器人邮包分拣系统

近日&#xff0c;香港邮政与全球仓储机器人引领者极智嘉(Geek)在其中央邮件中心联手建立全港首个机器人包裹分拣系统。该全新系统采用极智嘉分运结合解决方案&#xff0c;每小时可处理达1,000个邮包&#xff0c;助力香港邮政利用创新科技简化邮包分拣流程、提升工作效率&#x…