17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍.
  
  根据我的面试经验而言,能在简历上写上原理、源码等关键词的,是非常具备核心竞争力的.上周和一个公众号粉丝交流面试情况如下
  
  面试的时候,把源码一波分析,令面试官虎躯一震!在一阵前戏过后,以为接下来无非就是身体的一顿抽搐一切变得索然无味,不料面试官来了句令剧情发生了反转
  
  "你对Dubbo源码这么熟悉,那请问你使用的时候,有没有遇到什么坑"
  
  我擦,毫无准备的他,菊花顿时一紧!此时就面临唬住了50K,唬不住就只能5K的局面,慌了!
  
  论如何反杀
  
  相信大家面试都遇到过类似问题,因为源码解析网上很多,很多人"考前突击"一下,但是遇到喜欢问细节的面试官,终究难逃法眼,无处遁形.遇到这个问题,我们如何反杀一波?那么我就从一次聊天记录说起,毕竟只有关注肥朝公众号,拥有真实场景的源码实战(非常重要),遇到这类问题,才不至于出现猛虎落泪的情形
  
  真实场景描述
  
  那么我们把业务相关去掉,抽取一个最简模型.我们在公司,一般都会有自己的自定义异常,然后这个自定义异常一般放在common.jar给其他模块依赖,比如我这里定义一个HelloException
  
  1public class HelloException extends RuntimeException {
  
  2
  
  3 public HelloException() {
  
  4 }
  
  5
  
  6 public HelloException(String message) {
  
  7 super(message);
  
  8 }
  
  9
  
  10}
  
  然后我们写一个最简单的Dubbo的demo,如下
  
  interface
  
  1public interface DemoService {
  
  2
  
  3 String sayHello(String name);
  
  4
  
  5}
  
  provider
  
  1public class DemoServiceImpl implements DemoService {
  
  2
  
  3 public String sayHello(String name) {
  
  4 throw new HelloException("公众号:肥朝");
  
  5 }
  
  6
  
  7}
  
  consumer
  
  1public class DemoAction {
  
  2
  
  3 private DemoService demoService;
  
  4
  
  5 public void setDemoService(DemoService demoService) {
  
  6 this.demoService = demoService;
  
  7 }
  
  8
  
  9 public void start() throws Exception {
  
  10 try {
  
  11 String hello = demoService.sayHello("公众号:肥朝");
  
  12 } catch (HelloException helloException) {
  
  13 System.out.println("这里捕获helloException异常");
  
  14 }
  
  15 }
  
  16
  
  17}
  
  按照聊天记录的描述,此时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 www.taoyang2vip.com = result.getException();
  
  7
  
  8 // 如果是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(www.michenggw.com ).equals(exceptionClass)) {
  
  18 return result;
  
  19 }
  
  20 }
  
  21 } catch (NoSuchMethodException e) {
  
  22 return result;
  
  23 }
  
  24
  
  25 // 未在方法签名上定义的异常,在服务器端打印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(www.xinghenyule.com).getName() + ": " + exception.getMessage(), exception);
  
  29
  
  30 // 异常类和接口类在同一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(www.jiahuayulpt.com).getName();
  
  38 if (className.startsWith("java.") || className.startsWith("javax.")) {
  
  39 return result;
  
  40 }
  
  41 // 是Dubbo本身的异常,直接抛出
  
  42 if (exception www.thd178.com/ instanceof RpcException) {
  
  43 return result;
  
  44 }
  
  45
  
  46 // 否则,包装成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(www.yongshi123.cn) + ", 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: www.tiaotiaoylzc.com" + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
  
  59 + ", exception: www.myzx1.com " + e.getClass(www.dfgjpt.com).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://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q
  
  Memory ordering obeys causality (memory ordering respects transitive visibility).
  
  Any two stores are seen in a consistent order www.078881.cn by processors other than those performing the stores
  
  Locked instructions have a total order
  
  examples
  
  Neither Loads Nor Stores Are Reordered with Like Operations
  
  Stores Are Not Reordered With www.yongxin7.com Earlier Loads
  
  Loads May Be Reordered with Earlier Stores to Different Locations
  
  Loads Are not Reordered with Older Stores to the Same Location

面试官问我,使用Dubbo有没有遇到一些坑?我笑了的更多相关文章

  1. 面试官问我,Redis分布式锁如何续期?懵了。

    前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...

  2. 每日一问:面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

    面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

  3. 面试官问,说一个你在工作非常有价值的bug

    如果你去参考面试,做足了准备,面对面试官员从容不迫,吐沫横飞的大谈自己的工作经历.突然,面试官横插一句:说一个你在工作非常有价值的bug.顿时,整个空气都仿佛都凝固了!“What?”... 我想没几个 ...

  4. 面试官问:JS的this指向

    前言 面试官出很多考题,基本都会变着方式来考察this指向,看候选人对JS基础知识是否扎实.读者可以先拉到底部看总结,再谷歌(或各技术平台)搜索几篇类似文章,看笔者写的文章和别人有什么不同(欢迎在评论 ...

  5. 当面试官问你sql优化的时候。。。

    当面试官问你有关sql优化的问题时,直接拿笔写给他: 8-select 9-distinct<column_list> 1-from left_table 3-<join_type& ...

  6. 面试官问你JS基本类型时他想知道什么?

    面试的时候我们经常会被问答js的数据类型.大部分情况我们会这样回答包括:1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Sym ...

  7. 面试官问线程安全的List,看完再也不怕了!

    最近在Java技术栈知识星球里面有球友问到了线程安全的 List: 扫码查看答案或加入知识星球 栈长在之前的文章<出场率比较高的一道多线程安全面试题>里面讲过 ArrayList 的不安全 ...

  8. 美团面试官问我一个字符的String.length()是多少,我说是1,面试官说你回去好好学一下吧

    本文首发于微信公众号:程序员乔戈里 public class testT { public static void main(String [] args){ String A = "hi你 ...

  9. 大厂面试官问你META-INF/spring.factories要怎么实现自动扫描、自动装配?

    大厂面试官问你META-INF/spring.factories要怎么实现自动扫描.自动装配?   很多程序员想面试进互联网大厂,但是也有很多人不知道进入大厂需要具备哪些条件,以及面试官会问哪些问题, ...

  10. 当阿里面试官问我:Java创建线程有几种方式?我就知道问题没那么简单

    这是最新的大厂面试系列,还原真实场景,提炼出知识点分享给大家. 点赞再看,养成习惯~ 微信搜索[武哥聊编程],关注这个 Java 菜鸟. 昨天有个小伙伴去阿里面试实习生岗位,面试官问他了一个老生常谈的 ...

随机推荐

  1. UOJ400/LOJ2553 CTSC2018 暴力写挂 边分治、虚树

    传送门--UOJ 传送门--LOJ 跟隔壁通道是一个类型的 要求的式子中有两个LCA,不是很方便,因为事实上在这种题目中LCA一般都是枚举的对象-- 第二棵树上的LCA显然是动不了的,因为没有其他的量 ...

  2. NOIp2018停课刷题记录

    Preface 老叶说了高中停课但是初中不停的消息后我就为争取民主献出一份力量 其实就是和老师申请了下让我们HW的三个人听课结果真停了 那么还是珍惜这次机会好好提升下自己吧不然就\(AFO\)了 Li ...

  3. [Spark][python]从 web log 中提取出 UserID 作为key 值,形成新的 RDD

    针对RDD, 使用 keyBy 来构筑 key-line 对: [training@localhost ~]$ cat webs.log 56.31.230.188 - 90700 "GET ...

  4. Intel x86_64 Architecture Background 1

    首先讲一下什么是Intel x86,x86是指intel的开发的一种32位指令集,从386开始时代开始的一直沿用至今,是一种cisc指令集.x84_64是x86 CPU开始迈向64位的时候,有2选择: ...

  5. 【终结版】C#常用函数和方法集汇总

    C#里面的常用的函数和方法非常重要,然而做题的时候会经常忘记这些封装好的方法,所以我总结一下 C#常用函数和方法集. [1]C#操作字符串的常用使用方法 在 C# 中,您可以使用字符数组来表示字符串, ...

  6. springboot+thymeleaf刨坑——首页加载js/css等失败解决方法

    在使用thymeleaf加载css或js样式,当我们进入登录页的时候发现,所有的样式都是加载失败的.原因是在新版中有这样一个坑……: 当我们设置了addInterceptors-注册拦截器的时候,通常 ...

  7. Linux运维笔记-日常操作命令总结(3)

    文本操作:sed sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作. sed命令行格式为: sed [-nefri] ‘c ...

  8. java内存溢出的解决思路

    原文地址:https://www.cnblogs.com/200911/p/3965108.html 内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能 ...

  9. php ajax登录注册

    用户登录与退出功能应用在很多地方,而在有些项目中,我们需要使用Ajax方式进行登录,登录成功后只刷新页面局部,从而提升了用户体验度.本文将使用PHP和jQuery来实现登录和退出功能. 准备数据库 本 ...

  10. Let the Balloon Rise HDU水题

    题意 让你统计字符串最多的那个串,并输出 分析 直接用map统计,不断更新最大值即可 代码 #include<iostream> #include<algorithm> #in ...