轉(zhuǎn)自:http://blog.csdn.net/wzl18/article/details/51249018
dubbo有自己的異常處理機(jī)制豫柬,當(dāng)服務(wù)端拋出一個(gè)dubbo可以處理傳遞的異常時(shí)霎箍,會(huì)直接在客戶(hù)端上再次拋出煌茴,由開(kāi)發(fā)者自己去處理。注意:這里說(shuō)的不是所有異常,而是dubbo可以處理傳遞的異常,具體這個(gè)后邊再說(shuō)包吝。
先看兩段代碼,接口代碼:
簡(jiǎn)單實(shí)現(xiàn):
這兩段代碼很簡(jiǎn)答源葫,先看getByNick方法诗越,根據(jù)用戶(hù)名稱(chēng)獲取用戶(hù)信息,里面有一個(gè)去空格的操作(主要為了觸發(fā)異常)息堂,正常調(diào)用是沒(méi)有問(wèn)題的嚷狞,但如果傳入null,就會(huì)拋出很常見(jiàn)且低級(jí)的空指針異常。我們看下調(diào)用代碼:
運(yùn)行后感耙,首先會(huì)打印{"id":0,"name":"某某"}褂乍,然后出現(xiàn)java.lang.NullPointerException持隧,一切在我們的預(yù)料內(nèi)即硼,dubbo把服務(wù)端的空指針異常傳遞給客戶(hù)端了。
正常來(lái)說(shuō)屡拨,空指針異常是不應(yīng)該出現(xiàn)的只酥,而且客戶(hù)端遇到這個(gè)錯(cuò)誤肯定直接懵了,所以我們做下簡(jiǎn)單的修改呀狼,服務(wù)端代碼:
客戶(hù)端再次調(diào)用結(jié)果:
結(jié)果友好了多裂允,甚至你可以直接對(duì)exception獲取異常信息作為輸出。
上邊提到過(guò)當(dāng)服務(wù)端拋出一個(gè)dubbo可以處理傳遞的異常時(shí)哥艇,會(huì)直接在客戶(hù)端上再次拋出绝编,但不是所有的異常都是dubbo可以處理傳遞的,如下邊的代碼:
這里我們模擬拋出了一個(gè)mybatis的異常貌踏,在客戶(hù)端調(diào)用會(huì)像上邊的結(jié)果一樣嗎十饥?答案是否定的,看下輸出結(jié)果:
不要感覺(jué)奇怪祖乳,這個(gè)也是在可以接受的范圍內(nèi)逗堵,因?yàn)镻ersistenceException異常類(lèi)在客戶(hù)端是不存在的,所以不可能接收到PersistenceException異常眷昆,dubbo把他進(jìn)行了封裝蜒秤。
針對(duì)這點(diǎn),在接口包中里面定義了一個(gè)全局的異常類(lèi)亚斋,注意一定是接口所在的工程中作媚,如:UicException(用戶(hù)模塊異常),這種方案也是官方建議的帅刊,服務(wù)端代碼如下:
錯(cuò)誤信息如下
這個(gè)正是我們想要的異常信息纸泡,上邊特別提到異常一定要在接口所在的工程中,如果異常類(lèi)不在接口工程中厚掷,而是在另一個(gè)服務(wù)端和客戶(hù)端都引入的包中呢弟灼?我們?cè)?jīng)碰到這樣一個(gè)情況,有一個(gè)common的異常類(lèi)放在一個(gè)很底層的工具包內(nèi)冒黑,接口工程引入了這個(gè)包田绑,在服務(wù)端拋出的異常都都是這個(gè)commonexception,一廂情愿的認(rèn)為客戶(hù)端會(huì)正常去捕獲處理commonexception抡爹。
但結(jié)果很意外掩驱,客戶(hù)端出現(xiàn)的異常跟上邊拋出的PersistenceException情況一樣,dubbo用RuntimException進(jìn)行了包裝,我們無(wú)法從異常中獲取有效的信息欧穴!遇到這種情況有點(diǎn)發(fā)懵民逼,這個(gè)異常類(lèi)在客戶(hù)端和服務(wù)端都有呀,為啥不能正確接收呢涮帘。還好之前看dubbo源碼的時(shí)候大概記得異常處理的位置拼苍,很好找到了目標(biāo)代碼:
看完源碼以后,做出了新的設(shè)計(jì)调缨,CommonException不變疮鲫,各個(gè)接口模塊(maven工程為單位)單獨(dú)定義異常對(duì)象繼承CommonException,每個(gè)模塊拋出自己的模塊異常(如用戶(hù)模塊拋出UicException)弦叶,客戶(hù)端中用CommonException統(tǒng)一捕獲處理俊犯。
這里還要定義兩個(gè)攔截器,首先是服務(wù)端伤哺,保證所有拋出的異常是當(dāng)前模塊的異常燕侠,代碼如下:
其次是客戶(hù)端的,保證異沉⒗颍可以正確的友好的輸出绢彤,所有CommonException可以直接輸出(獲取根據(jù)錯(cuò)誤碼獲取錯(cuò)誤信息),非CommonException異常根據(jù)自己需要去處理桃序,如果是dubbo自帶異痴认海肯定要屏蔽異常信息,如打印日志后輸出“網(wǎng)絡(luò)異趁叫埽”奇适。
還有另一種dubbo調(diào)用方案,普通service層外邊嵌套一層用來(lái)做dubbo的服務(wù)芦鳍,普通service層處理了事務(wù)之類(lèi)嚷往,dubbo服務(wù)層每一個(gè)方法都是客戶(hù)端要引用的,直接調(diào)用普通service層方法柠衅,但做了手動(dòng)的try catch處理皮仁,封裝自己的返回碼,客戶(hù)端只需要根據(jù)返回碼去做處理菲宴,這種開(kāi)發(fā)成本和文檔成本有點(diǎn)高贷祈,沒(méi)太深入去考慮。
以上是我自己工作中的dubbo異常實(shí)踐喝峦,以后會(huì)繼續(xù)寫(xiě)些其他的心得势誊,記錄自己的成長(zhǎng)。