千家信息网

面试官问我,使用Dubbo有没有遇到一些坑?我笑了。

发表于:2025-12-03 作者:千家信息网编辑
千家信息网最后更新 2025年12月03日,前言17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍.根据我的面试经验而言
千家信息网最后更新 2025年12月03日面试官问我,使用Dubbo有没有遇到一些坑?我笑了。

前言

17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍.

根据我的面试经验而言,能在简历上写上原理、源码等关键词的,是非常具备核心竞争力的.上周和一个公众号粉丝交流面试情况如下

面试的时候,把源码一波分析,令面试官虎躯一震!在一阵前戏过后,以为接下来无非就是身体的一顿抽搐一切变得索然无味,不料面试官来了句令剧情发生了反转

"你对Dubbo源码这么熟悉,那请问你使用的时候,有没有遇到什么坑"

我擦,毫无准备的他,菊花顿时一紧!此时就面临唬住了50K,唬不住就只能5K的局面,慌了!

论如何反杀

相信大家面试都遇到过类似问题,因为源码解析网上很多,很多人"考前突击"一下,但是遇到喜欢问细节的面试官,终究难逃法眼,无处遁形.遇到这个问题,我们如何反杀一波?那么我就从一次聊天记录说起,毕竟只有关注肥朝公众号,拥有真实场景的源码实战(非常重要),遇到这类问题,才不至于出现猛虎落泪的情形

真实场景描述

那么我们把业务相关去掉,抽取一个最简模型.我们在公司,一般都会有自己的自定义异常,然后这个自定义异常一般放在common.jar给其他模块依赖,比如我这里定义一个HelloException

1public class HelloException extends RuntimeException {23    public HelloException() {4    }56    public HelloException(String message) {7        super(message);8    }910}

然后我们写一个最简单的Dubbo的demo,如下

interface

1public interface DemoService {23    String sayHello(String name);45}

provider

1public class DemoServiceImpl implements DemoService {23    public String sayHello(String name) {4        throw new HelloException("公众号:肥朝");5    }67}

consumer

1public class DemoAction {23    private DemoService demoService;45    public void setDemoService(DemoService demoService) {6        this.demoService = demoService;7    }89    public void start() throws Exception {10        try {11            String hello = demoService.sayHello("公众号:肥朝");12        } catch (HelloException helloException) {13            System.out.println("这里捕获helloException异常");14        }15    }1617}

按照聊天记录的描述,此时consumer调用provider,provider抛出HelloException.但是consumer捕获到的,却不是HelloException.

那么我们运行看看

果然如该同事所言.为什么会这样呢?之前没看过肥朝Dubbo源码解析系列的同学这种时候往往采用最低效的解决办法,把异常栈往微信群一丢,各种求助.但是往往毫无收获,然后感叹社会为何如此冷漠!

但是相信公众号的老粉丝们早已掌握阅读源码的技能,和肥朝一样坐怀不乱,九浅一深直入源码.出现异常我们首先看一下异常栈

除非撸多了看不清(建议戒撸),否则这行异常和肥朝一样,就像漆黑中的萤火虫一样,那么鲜明,那么出众

1com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:108)

那么我们一探究竟

1    public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {2        try {3            Result result = invoker.invoke(invocation);4            if (result.hasException() && GenericService.class != invoker.getInterface()) {5                try {6                    Throwable exception = result.getException();78                    // 如果是checked异常,直接抛出9                    if (! (exception instanceof RuntimeException) && (exception instanceof Exception)) {10                        return result;11                    }12                    // 在方法签名上有声明,直接抛出13                    try {14                        Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());15                        Class[] exceptionClassses = method.getExceptionTypes();16                        for (Class exceptionClass : exceptionClassses) {17                            if (exception.getClass().equals(exceptionClass)) {18                                return result;19                            }20                        }21                    } catch (NoSuchMethodException e) {22                        return result;23                    }2425                    // 未在方法签名上定义的异常,在服务器端打印ERROR日志26                    logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()27                            + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()28                            + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);2930                    // 异常类和接口类在同一jar包里,直接抛出31                    String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());32                    String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());33                    if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){34                        return result;35                    }36                    // 是JDK自带的异常,直接抛出37                    String className = exception.getClass().getName();38                    if (className.startsWith("java.") || className.startsWith("javax.")) {39                        return result;40                    }41                    // 是Dubbo本身的异常,直接抛出42                    if (exception instanceof RpcException) {43                        return result;44                    }4546                    // 否则,包装成RuntimeException抛给客户端47                    return new RpcResult(new RuntimeException(StringUtils.toString(exception)));48                } catch (Throwable e) {49                    logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost()50                            + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()51                            + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);52                    return result;53                }54            }55            return result;56        } catch (RuntimeException e) {57            logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()58                    + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()59                    + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);60            throw e;61        }62    }
1.如果是checked异常,直接抛出.很明显,我们的HelloException是RuntimeException,不符合2.在方法签名上有声明,直接抛出.很明显,我们接口并未声明该异常,不符合3.异常类和接口类在同一jar包里,直接抛出.很明显,我们的异常类是在common.jar的,接口是在api.jar的,不符合4.是JDK自带的异常,直接抛出.很明显,这个HelloException是我们自定义的,不符合5.是Dubbo本身的异常(RpcException),直接抛出.很明显,这个HelloException是我们自定义的,和RpcException几乎没有半毛钱关系.6.否则,包装成RuntimeException抛给客户端.因为以上5点均不满足,所以该异常会被包装成RuntimeException异常抛出(重要)

这也就是为什么我们catchHelloException是catch不到的,因为他包装成RuntimeException了

Dubbo为什么这么设计

也许你看到这里会觉得这个判断好坑.Dubbo为什么要这么设计?我们看源码,最重要的是知道作者为什么这么设计,只有知道为什么这么设计才是经过了深度的思考,否则看时高潮,看后就忘.讲清楚为什么这么设计,也是大家关注肥朝公众号的一个重要原因.

其实Dubbo的这个考虑,是基于序列化来考虑的.你想想,如果provider抛出一个仅在provider自定义的一个异常,那么该异常到达consumer,明显是无法序列化的.所以你注意看Dubbo的判断.我们来看下他的判断

1.如果是checked异常,直接抛出.很明显,我们的HelloException是RuntimeException,不符合2.在方法签名上有声明,直接抛出.很明显,我们接口并未声明该异常,不符合3.异常类和接口类在同一jar包里,直接抛出.很明显,我们的异常类是在common.jar的,接口是在api.jar的,不符合4.是JDK自带的异常,直接抛出.很明显,这个HelloException是我们自定义的,不符合5.是Dubbo本身的异常(RpcException),直接抛出.很明显,这个HelloException是我们自定义的,和RpcException几乎没有半毛钱关系.6.否则,包装成RuntimeException抛给客户端.因为以上5点均不满足,所以该异常会被包装成RuntimeException异常抛出(重要)

如何解决

既然都知道了原理了,那么很好解决,我随便列举一下,比如从规范上要求业务方接口声明HelloException

写在最后

当然肥朝面试的时候,也曾经被问过类似问题,你用XXX有没有遇到过什么坑.在一波操作猛如虎的分析下,面试官说

"你真帅".

肥朝会心一笑

结果他却说

"你笑起来更帅"!

免费Java资料领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高并发分布式、大数据、机器学习等技术。 传送门: https://jq.qq.com/?_wv=1027&k=5F79bMq

明显 源码 接口 公众 重要 时候 粉丝 设计 方法 是在 问题 一波 包装 客户 客户端 冲动 业务 原理 只有 场景 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 秦淮区网络软件开发 pdb蛋白数据库 matlab数据库后缀名 怎么查看服务器的自动运行代码 增长引擎网络技术有限公司怎么样 烟台奥商网络技术有限公司 rust能创建服务器吗 水仙网络技术工作室 管理员已禁止程序启动服务器 浪潮服务器磁盘格式化怎么恢复 mysql数据库面试代码题 英雄联盟各服务器免费英雄列表 辽宁智慧养老软件开发系统 软件开发过程文档如何写作 2核云服务器怎样弄成1核的 关于网络安全小知识十条 服务器驱动文件怎么导入手机 色选机软件开发 开展了网络安全岗位培训 命令方块创建服务器所有指令 嘉定区电商软件开发定制价格 小班网络安全教育课图片 hlwsccl服务器 linux上搭建服务器 阿里云容器服务器 计算机等级数据库考试题 一个数据库怎么在两个电脑上用 主机使命召唤先锋连不上服务器 防震减灾网络安全手抄报 图书馆数据库技术
0