溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

發(fā)布時(shí)間:2020-08-06 21:39:03 來源:ITPUB博客 閱讀:177 作者:JAVA架構(gòu) 欄目:軟件技術(shù)

前言

17年的時(shí)候,因?yàn)橐粫r(shí)沖動(dòng)沒把持住(當(dāng)然最近也有粉絲叫我再?zèng)_動(dòng)一把再更新一波),結(jié)合面試題寫了一個(gè)系列的Dubbo源碼解析.目前公眾號大部分粉絲都是之前的粉絲,這里不過多介紹.

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

根據(jù)我的面試經(jīng)驗(yàn)而言,能在簡歷上寫上原理、源碼等關(guān)鍵詞的,是非常具備核心競爭力的.上周和一個(gè)公眾號粉絲交流面試情況如下

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

面試的時(shí)候,把源碼一波分析,令面試官虎軀一震!在一陣前戲過后,以為接下來無非就是身體的一頓抽搐一切變得索然無味,不料面試官來了句令劇情發(fā)生了反轉(zhuǎn)

"你對Dubbo源碼這么熟悉,那請問你使用的時(shí)候,有沒有遇到什么坑"

我擦,毫無準(zhǔn)備的他,菊花頓時(shí)一緊!此時(shí)就面臨唬住了50K,唬不住就只能5K的局面,慌了!

論如何反殺

相信大家面試都遇到過類似問題,因?yàn)樵创a解析網(wǎng)上很多,很多人"考前突擊"一下,但是遇到喜歡問細(xì)節(jié)的面試官,終究難逃法眼,無處遁形.遇到這個(gè)問題,我們?nèi)绾畏礆⒁徊?那么我就從一次聊天記錄說起,畢竟只有關(guān)注肥朝公眾號,擁有真實(shí)場景的源碼實(shí)戰(zhàn)(非常重要),遇到這類問題,才不至于出現(xiàn)猛虎落淚的情形

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

真實(shí)場景描述

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

那么我們把業(yè)務(wù)相關(guān)去掉,抽取一個(gè)最簡模型.我們在公司,一般都會(huì)有自己的自定義異常,然后這個(gè)自定義異常一般放在common.jar給其他模塊依賴,比如我這里定義一個(gè)HelloException

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

然后我們寫一個(gè)最簡單的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}

按照聊天記錄的描述,此時(shí)consumer調(diào)用provider,provider拋出HelloException.但是consumer捕獲到的,卻不是HelloException.

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

那么我們運(yùn)行看看

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

果然如該同事所言.為什么會(huì)這樣呢?之前沒看過肥朝Dubbo源碼解析系列的同學(xué)這種時(shí)候往往采用最低效的解決辦法,把異常棧往微信群一丟,各種求助.但是往往毫無收獲,然后感嘆社會(huì)為何如此冷漠!

但是相信公眾號的老粉絲們早已掌握閱讀源碼的技能,和肥朝一樣坐懷不亂,九淺一深直入源碼.出現(xiàn)異常我們首先看一下異常棧

面試官問我,使用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                    // 未在方法簽名上定義的異常,在服務(wù)器端打印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自帶的異常,直接拋出.很明顯,這個(gè)HelloException是我們自定義的,不符合5.是Dubbo本身的異常(RpcException),直接拋出.很明顯,這個(gè)HelloException是我們自定義的,和RpcException幾乎沒有半毛錢關(guān)系.6.否則,包裝成RuntimeException拋給客戶端.因?yàn)橐陨?點(diǎn)均不滿足,所以該異常會(huì)被包裝成RuntimeException異常拋出(重要)

這也就是為什么我們catchHelloException是catch不到的,因?yàn)樗b成RuntimeException了

Dubbo為什么這么設(shè)計(jì)

也許你看到這里會(huì)覺得這個(gè)判斷好坑.Dubbo為什么要這么設(shè)計(jì)?我們看源碼,最重要的是知道作者為什么這么設(shè)計(jì),只有知道為什么這么設(shè)計(jì)才是經(jīng)過了深度的思考,否則看時(shí)高潮,看后就忘.講清楚為什么這么設(shè)計(jì),也是大家關(guān)注肥朝公眾號的一個(gè)重要原因.

其實(shí)Dubbo的這個(gè)考慮,是基于序列化來考慮的.你想想,如果provider拋出一個(gè)僅在provider自定義的一個(gè)異常,那么該異常到達(dá)consumer,明顯是無法序列化的.所以你注意看Dubbo的判斷.我們來看下他的判斷

1.如果是checked異常,直接拋出.很明顯,我們的HelloException是RuntimeException,不符合2.在方法簽名上有聲明,直接拋出.很明顯,我們接口并未聲明該異常,不符合3.異常類和接口類在同一jar包里,直接拋出.很明顯,我們的異常類是在common.jar的,接口是在api.jar的,不符合4.是JDK自帶的異常,直接拋出.很明顯,這個(gè)HelloException是我們自定義的,不符合5.是Dubbo本身的異常(RpcException),直接拋出.很明顯,這個(gè)HelloException是我們自定義的,和RpcException幾乎沒有半毛錢關(guān)系.6.否則,包裝成RuntimeException拋給客戶端.因?yàn)橐陨?點(diǎn)均不滿足,所以該異常會(huì)被包裝成RuntimeException異常拋出(重要)

如何解決

既然都知道了原理了,那么很好解決,我隨便列舉一下,比如從規(guī)范上要求業(yè)務(wù)方接口聲明HelloException

寫在最后

當(dāng)然肥朝面試的時(shí)候,也曾經(jīng)被問過類似問題,你用XXX有沒有遇到過什么坑.在一波操作猛如虎的分析下,面試官說

"你真帥".

肥朝會(huì)心一笑

面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。

結(jié)果他卻說

"你笑起來更帥"!

免費(fèi)Java資料領(lǐng)取,涵蓋了Java、RedisMongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高并發(fā)分布式、大數(shù)據(jù)、機(jī)器學(xué)習(xí)等技術(shù)。 傳送門: https://jq.qq.com/?_wv=1027&k=5F79bMq

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI