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

2021-03-01 中間件興趣圈
前言

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 = 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().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().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().getName();
38                    if (className.startsWith("java.") || className.startsWith("javax.")) {
39                        return result;
40                    }
41                    // 是Dubbo本身的異常,直接拋出
42                    if (exception 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() + ", 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異常和RuntimeException是不同類型,強行包裝可能會出現類型轉換錯誤,因此不包,直接拋出

2.方法籤名上有聲明.方法籤名上有聲明,如果這個異常是provider.jar中定義的,因為consumer是依賴api.jar的,而不是依賴provider.jar.那麼編譯都編譯不過,如果能編譯得過,說明consumer是能依賴到這個異常的,因此序列化不會有問題,直接拋出

3.異常類和接口類在同一jar包裡.provider和consumer都依賴api,如果異常在這個api,那序列化也不會有問題,直接拋出

4.是JDK自帶的異常,直接拋出.provider和consumer都依賴jdk,序列化也不會有問題,直接拋出

5.是Dubbo本身的異常(RpcException),直接拋出.provider和consumer都依賴Dubbo,序列化也不會有問題,直接拋出

6.否則,包裝成RuntimeException拋給客戶端.此時,就有可能出現我說的那種,這個異常是provider.jar自定義的,那麼provider拋出的時候進行序列化,因為consumer沒有依賴provider.jar,所以異常到達consumer時,根本無法反序列化.但是包裝成了RuntimeException異常則不同,此時異常就是JDK中的類了,到哪都能序列化.

如何解決

既然都知道了原理了,那麼很好解決,我隨便列舉一下,比如從規範上要求業務方接口聲明HelloException

寫在最後

當然肥朝面試的時候,也曾經被問過類似問題,你用XXX有沒有遇到過什麼坑.在一波操作猛如虎的分析下,面試官說

"你真帥".

肥朝會心一笑


結果他卻說

"你笑起來更帥"!

歡迎關注『中間件興趣圈』,交流中間件、架構設計、實戰應用等技術課題。

相關焦點

  • 面試時,當面試官問:你有沒有需要問我的嗎?該如何機智回答?
    相信大家面試時或許會經歷過這麼一個過程:面試到最後,面試官往往都會問:「你有沒有什麼需要問我的?」這個時候該如何去回答。恰當的回答可能會為你再一次加分,不合適的的回答會讓你之前的努力功虧一窺。這個時候你肯定有一些實際性的問題,增強對工作環境的了解。要是你只是流水線的面試,對面試的工作環境都不在乎,毫無疑問你對工作的渴望程度也不高。態度決定一切,你現在都不在乎面試了,對工作還能在乎到哪裡去。(2)確保應聘者沒有誤解面試官給你提問的機會,是讓你對面試過程當中與你交流的內容,對不明白的地方的可以再一次諮詢。
  • 面試官:「你有什麼要問我的嗎?」,牢記這3個點,不懂別亂問
    我們在參加面試,面試到了最後一個環節的時候,面試官總會問你:你還有什麼要問我的嗎?你這個時候你們是怎麼說的呢?是有問題還是沒有問題呢?小明在參加面試的時候,曾經就在這個問題上栽過坑,當面試官問小明有沒有什麼問題要問的時候,小明回答說,基本上沒有什麼問題要問你了。
  • 面試官問「你能在我公司幹多久?」老闆:「呵呵,你可以走了」
    老闆問他「如果讓你通過面試,你能在公司幹多久」,大彬說「幹到公司倒閉為止」。老闆黑臉,又問「公司倒不了的,你能一直幹下去?」,大彬說「錢給到位就行了,比如招聘上寫的」。老闆笑了笑「你可以走了」。01 避免喊口號,不講空話很多面試還是非常正經的,不會那麼坑人,人才的流失率確實也是各個公司人才管理關注的重點,遇到合適的人才,不管是老闆還是人力經理都會在意『能幹多久「,甚至於在這點上談不合,再優秀的人才也不敢要。所以遇到面試官問「你能在我公司幹多久」,要謹慎回答,避免錯失合適的崗位,讓我們在前面的努力功虧一簣。
  • 面試官讓我手寫算法,HR小姐姐問我米字加一筆是什麼字?怎麼答?
    緊接著,HR小姐姐問了他一個問題:米字加一筆是什麼字?求職者一時語塞,沒答出來,面試官只好讓他回去等通知。其實,md5算法已經很成熟,在使用過程中只需要調個API就能實現了,面試官卻還讓求職者盲寫這個算法,是要做什麼呢?
  • 面試時,面試官提出跟工作無關的難題,面試官有何意圖?
    有些面試官會提問一些跟工作無關的問題,甚至是刁難應聘著,其實這些問題也不是面試官故意用來刁難應聘者的,這些問題也是為了為自己的企業篩選人才而精心挑選出來的,自然有他們的考察目的。接下來的一個企業面試案例,帶你看透企業招聘時的難題,到底有什麼用意!
  • 面試官:你可以向我提出問題,年輕小夥巧問過面試,這3點需牢記
    在我看到過的一檔綜藝節目,跟實習相關的節目,裡面有一個令我拍手叫好的一個問題,一般面試當中,面試官都會在結尾讓你提出問題,有的是兩個,有的是一個,問題不在多少,在於怎麼問,他是這麼問的:」各位面試官希望在錄取的實習生中,最希望看到這名實習生能夠具備什麼樣的品質?「,正是因為這個問題,巧問過了面試。
  • 面試官:我兒子是你兒子的爸爸,那我是你的誰?女子妙回復被錄用
    想要擁有一份好工作,進入一家好公司,面試就是其不可缺少的環節。面試是一家公司考驗你是否具有公司要求的專業能力、人品素質和反應力的環節。如今的面試,面試官不會再滿足於問你一些專業性的知識,而是更偏向於設計一些專門考驗面試者綜合素質的問題。
  • 面試官問:「你的興趣愛好是什麼?」這樣回答,面試官最滿意
    面試官時間是很寶貴的,在短短一個小時之內,需要對候選人深入的了解,所以問任何問題都是有目的性的,那面試官問:「你的興趣愛好是什麼?」有什麼目的呢?面試官問你有什麼體育運動方面的愛好,他可不是想尋找球友,而是想從側面了解你的工作精力和活力以及身體健康程度。面試官問你是否喜歡看書,他可能是想從側面看看你是否愛好學習。同時, 面試官也想了解候選人是否有不良嗜好,如果這個不良嗜好對於崗位有影響,可能就不不能要。
  • 面試官:我兒子是你兒子的爸,那你叫我什麼?小夥神回復被錄取
    想進一家好的公司,面試是必不可少的,面試是一個公司考驗你專業能力,人品能力和反應能力的階段。相信很多出來找工作的人,都已經經歷過各種各樣的面試的,現如今的面試官他們不再會滿足於問你一些專業上的問題,會專門設計一些話題來考驗你的綜合素質,以及思維變通能力面試官也是費盡心機啊。
  • 面試官問你在未來職場的規劃,傻瓜不知所措,聰明人這樣說
    面試官問你在未來職場的規劃,傻瓜不知所措,聰明人這樣說前不久,小編收到一個讀者的私信,這個私信的同學說自己是今年剛畢業的大學生,前幾天自己找工作遇到了一個讓自己非常尷尬的事情。這位同學在面試的時候,前面表現的非常不錯,面試官問的那些專業課,在學校的表現等等都回答得挺熟練,自己和面試官都覺得很滿意,後來面試官話鋒一轉問這個同學他對於自己的人生規劃是什麼?將來有什麼打算?他當時就感覺到懵了。不知道要怎麼回答。
  • 面試官:我的牙齒有菜葉如何提醒我?聰明人都知道這樣回答
    在面試當中,很多時候我們都有可能碰到一些比較奇怪的問題,這主要是因為面試官有著他們自己獨特的考察目的。現在,很多面試都改成了在網上面試,這同樣對面試者的能力就有了更高的要求,同時考察的方面也更為詳細複雜。
  • 當面試官問你「你期望的薪資是多少」時,實際上是在問什麼?
    看到不少朋友還在找工作,在這裡分享一點面試經驗:01回答面試官問題要弄懂潛臺詞1、 看你的期望薪資與公司可以提供的薪資是否匹配在面試官的問題快到尾聲時,他們都會問「你期望的薪資是多少」,他們並不僅僅是為了知道你期望薪資的這個數字,而是為了輔助自己判斷
  • 面試官:如果你是我,你會對自己說什麼?小夥的答案也是沒誰了
    面試題有多奇葩,你想都想不到。什麼衛生巾啊,拉鏈開了啊之類的,全出來了。但是,就算再奇葩,都比不上阿磊前段時間遇到的面試題:如果你是我,你會對自己說什麼?50多人應聘,只剩下三個進入最後的面試,阿磊運氣不錯,赫然在其中。面試官是一個美女,高跟鞋噠噠的,很有氣勢,問題也很霸氣:「如果你是我,你會對自己說什麼?」第一個面試者,聽到這個問題,想都沒想:「你這意思是我面試我自己嗎?這種如果有意義嗎?
  • 面試官:我女兒是你女兒的媽媽,我是你的誰?小夥機智應對被錄用
    在面試當中,很多時候我們都有可能碰到一些比較奇怪的問題,這主要是因為面試官有著他們自己獨特的考察目的。現在,很多面試都改成了在網上面試,這同樣對面試者的能力就有了更高的要求,同時考察的方面也更為詳細複雜。
  • 面試官:「你還有什麼問題要問我嗎」該怎麼回答?職場高人這樣回
    面試官:「你還有什麼問題要問我嗎」該怎麼回答?職場高人這樣回當我們在求職的時候,開始的時候是通過自己投簡歷,然後讓一些公司對你的簡歷情況產生一定的興趣,從而通過和你交談的情況,來考慮要不要給你一次面試的機會。
  • 面試時,面試官問你什麼時候能到崗,優秀的人這樣回答
    有很多人在生活中是一個特別能說的人,但是一旦到了關鍵的面試環節時,就不像生活中的那個樣子了。有時候後因為不謹慎就會犯錯誤。在面試中,很多面試官會問一些看起來和工作毫不相關的問題,有些問題看起來非常普通,但是一旦回答錯誤就會讓面試官對自己的面試印象產生敗績。這樣就影響了自己的面試成績。
  • 槓精邏輯:面試官不該問我是什麼學校畢業的,簡歷上寫著呢
    據說,面試官問這類問題,讓應聘者最反感!為什麼呢?因為應聘者覺得面試官很無腦——簡歷上寫的不都有嗎?還問我是什麼專業和學校。心裏面覺得,你煩不煩啊。這個說法,贏來了不少點讚。但是站在面試官一方,有人卻並不認同這一點,他也有自己的理由——「看簡歷」和「聽簡歷」是兩回事,讓你自我簡短介紹,能讓面試官感受到一些在簡歷中看不到的東西。
  • 面試中的跳過那些坑——面試結尾篇
    今日分享你面試中的跳過那些坑---面試結尾篇 -在上一期的分享中我們介紹了面試技巧和注意事項天將降大任於斯人也,必先苦其心志,勞其筋骨,餓其體膚,空乏其身。請輸入用戶名:麥兜兒!請輸入密碼:一隻快樂的肥豬!
  • 面試官:我和你的老婆誰最漂亮?小夥機智回答獲稱讚,被公司錄用
    小夥機智回答獲稱讚,被公司錄用現在的面試,和以往有了些許的區別,很多時候,面試官在問這些問題的時候,都是從側面的去了解面試者的一個綜合能力,這些能力是在專業能力以及個人的工作經驗之外的,面試官的另一種對於面試者的一個了解,美名其曰更好的了解面試者的一個能力,為公司篩選出了最合適的一個員工,而面試者對於這種問題 ,也是有著不同的回答,畢竟每個人對於回答這種問題所抱的心態也是不一樣的。
  • 面試官口頭給offer卻沒錄用,是我太傻還是HR太不靠譜?
    小米非常高興,一想到自己的工作有了著落,直接乾脆推掉了其他的面試,安心等待面試官給他發送offer和讓他去公司上班的消息。可是小米左等右等,三天過去了沒有任何消息,連offer都沒有。小米給面試官打過去才知道,原來自己最後沒有被選上。小米可以說是非常懊惱覺得面試官欺騙了自己,害得自己錯過了其他的面試機會不說,還要出重新投遞簡歷重新面試,可以說有苦難言啊!