日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
Spring Cloud實(shí)戰(zhàn)小貼士:Zuul統(tǒng)一異常處理(二)

在前幾天發(fā)布的《Spring Cloud實(shí)戰(zhàn)小貼士:Zuul統(tǒng)一異常處理(一)》一文中,我們?cè)敿?xì)說(shuō)明了當(dāng)Zuul的過(guò)濾器中拋出異常時(shí)會(huì)發(fā)生客戶端沒(méi)有返回任何內(nèi)容的問(wèn)題以及針對(duì)這個(gè)問(wèn)題的兩種解決方案:一種是通過(guò)在各個(gè)階段的過(guò)濾器中增加try-catch塊,實(shí)現(xiàn)過(guò)濾器內(nèi)部的異常處理;另一種是利用error類(lèi)型過(guò)濾器的生命周期特性,集中地處理pre、route、post階段拋出的異常信息。通常情況下,我們可以將這兩種手段同時(shí)使用,其中***種是對(duì)開(kāi)發(fā)人員的基本要求;而第二種是對(duì)***種處理方式的補(bǔ)充,以防止一些意外情況的發(fā)生。這樣的異常處理機(jī)制看似已經(jīng)***,但是如果在多一些應(yīng)用實(shí)踐或源碼分析之后,我們會(huì)發(fā)現(xiàn)依然存在一些不足。

創(chuàng)新互聯(lián)公司-專(zhuān)業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性?xún)r(jià)比陽(yáng)東網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式陽(yáng)東網(wǎng)站制作公司更省心,省錢(qián),快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋陽(yáng)東地區(qū)。費(fèi)用合理售后完善,十載實(shí)體公司更值得信賴(lài)。

不足之處

下面,我們不妨跟著源碼來(lái)看看,到底上面的方案還有哪些不足之處需要我們注意和進(jìn)一步優(yōu)化的。先來(lái)看看外部請(qǐng)求到達(dá)API網(wǎng)關(guān)服務(wù)之后,各個(gè)階段的過(guò)濾器是如何進(jìn)行調(diào)度的:

 
 
 
  1. try { 
  2.     preRoute(); 
  3. } catch (ZuulException e) { 
  4.     error(e); 
  5.     postRoute(); 
  6.     return; 
  7. try { 
  8.     route(); 
  9. } catch (ZuulException e) { 
  10.     error(e); 
  11.     postRoute(); 
  12.     return; 
  13. try { 
  14.     postRoute(); 
  15. } catch (ZuulException e) { 
  16.     error(e); 
  17.     return; 

上面代碼源自com.netflix.zuul.http.ZuulServlet的service方法實(shí)現(xiàn),它定義了Zuul處理外部請(qǐng)求過(guò)程時(shí),各個(gè)類(lèi)型過(guò)濾器的執(zhí)行邏輯。從代碼中我們可以看到三個(gè)try-catch塊,它們依次分別代表了pre、route、post三個(gè)階段的過(guò)濾器調(diào)用,在catch的異常處理中我們可以看到它們都會(huì)被error類(lèi)型的過(guò)濾器進(jìn)行處理(之前使用error過(guò)濾器來(lái)定義統(tǒng)一的異常處理也正是利用了這個(gè)特性);error類(lèi)型的過(guò)濾器處理完畢之后,除了來(lái)自post階段的異常之外,都會(huì)再被post過(guò)濾器進(jìn)行處理。而對(duì)于從post過(guò)濾器中拋出異常的情況,在經(jīng)過(guò)了error過(guò)濾器處理之后,就沒(méi)有其他類(lèi)型的過(guò)濾器來(lái)接手了,這就是使用之前所述方案存在不足之處的根源。

分析與優(yōu)化

回想一下之前實(shí)現(xiàn)的兩種異常處理方法,其中非常核心的一點(diǎn),這兩種處理方法都在異常處理時(shí)候往請(qǐng)求上下文中添加了一系列的error.*參數(shù),而這些參數(shù)真正起作用的地方是在post階段的SendErrorFilter,在該過(guò)濾器中會(huì)使用這些參數(shù)來(lái)組織內(nèi)容返回給客戶端。而對(duì)于post階段拋出異常的情況下,由error過(guò)濾器處理之后并不會(huì)在調(diào)用post階段的請(qǐng)求,自然這些error.*參數(shù)也就不會(huì)被SendErrorFilter消費(fèi)輸出。所以,如果我們?cè)谧远xpost過(guò)濾器的時(shí)候,沒(méi)有正確的處理異常,就依然有可能出現(xiàn)日志中沒(méi)有異常并且請(qǐng)求響應(yīng)內(nèi)容為空的問(wèn)題。我們可以通過(guò)修改之前ThrowExceptionFilter的filterType修改為post來(lái)驗(yàn)證這個(gè)問(wèn)題的存在,注意去掉try-catch塊的處理,讓它能夠拋出異常。

解決上述問(wèn)題的方法有很多種,比如最直接的我們可以在實(shí)現(xiàn)error過(guò)濾器的時(shí)候,直接來(lái)組織結(jié)果返回就能實(shí)現(xiàn)效果,但是這樣的缺點(diǎn)也很明顯,對(duì)于錯(cuò)誤信息組織和返回的代碼實(shí)現(xiàn)就會(huì)存在多份,這樣非常不易于我們?nèi)蘸蟮拇a維護(hù)工作。所以為了保持對(duì)異常返回處理邏輯的一致,我們還是希望將post過(guò)濾器拋出的異常能夠交給SendErrorFilter來(lái)處理。

在前文中,我們已經(jīng)實(shí)現(xiàn)了一個(gè)ErrorFilter來(lái)捕獲pre、route、post過(guò)濾器拋出的異常,并組織error.*參數(shù)保存到請(qǐng)求的上下文中。由于我們的目標(biāo)是沿用SendErrorFilter,這些error.*參數(shù)依然對(duì)我們有用,所以我們可以繼續(xù)沿用該過(guò)濾器,讓它在post過(guò)濾器拋出異常的時(shí)候,繼續(xù)組織error.*參數(shù),只是這里我們已經(jīng)無(wú)法將這些error.*參數(shù)再傳遞給SendErrorFitler過(guò)濾器來(lái)處理了。所以,我們需要在ErrorFilter過(guò)濾器之后再定義一個(gè)error類(lèi)型的過(guò)濾器,讓它來(lái)實(shí)現(xiàn)SendErrorFilter的功能,但是這個(gè)error過(guò)濾器并不需要處理所有出現(xiàn)異常的情況,它僅對(duì)post過(guò)濾器拋出的異常才有效。根據(jù)上面的思路,我們完全可以創(chuàng)建一個(gè)繼承自SendErrorFilter的過(guò)濾器,就能復(fù)用它的run方法,然后重寫(xiě)它的類(lèi)型、順序以及執(zhí)行條件,實(shí)現(xiàn)對(duì)原有邏輯的復(fù)用,具體實(shí)現(xiàn)如下:

 
 
 
  1. try { 
  2.     preRoute(); 
  3. } catch (ZuulException e) { 
  4.     error(e); 
  5.     postRoute(); 
  6.     return; 
  7. try { 
  8.     route(); 
  9. } catch (ZuulException e) { 
  10.     error(e); 
  11.     postRoute(); 
  12.     return; 
  13. try { 
  14.     postRoute(); 
  15. } catch (ZuulException e) { 
  16.     error(e); 
  17.     return; 

到這里,我們?cè)谶^(guò)濾器調(diào)度上的實(shí)現(xiàn)思路已經(jīng)很清晰了,但是又有一個(gè)問(wèn)題出現(xiàn)在我們面前:怎么判斷引起異常的過(guò)濾器是來(lái)自什么階段呢?(shouldFilter方法該如何實(shí)現(xiàn))對(duì)于這個(gè)問(wèn)題,我們***反應(yīng)會(huì)寄希望于請(qǐng)求上下文RequestContext對(duì)象,可是在查閱文檔和源碼后發(fā)現(xiàn)其中并沒(méi)有存儲(chǔ)異常來(lái)源的內(nèi)容,所以我們不得不擴(kuò)展原來(lái)的過(guò)濾器處理邏輯,當(dāng)有異常拋出的時(shí)候,記錄下拋出異常的過(guò)濾器,這樣我們就可以在ErrorExtFilter過(guò)濾器的shouldFilter方法中獲取并以此判斷異常是否來(lái)自post階段的過(guò)濾器了。

為了擴(kuò)展過(guò)濾器的處理邏輯,為請(qǐng)求上下文增加一些自定義屬性,我們需要深入了解一下Zuul過(guò)濾器的核心處理器:com.netflix.zuul.FilterProcessor。該類(lèi)中定義了下面過(guò)濾器調(diào)用和處理相關(guān)的核心方法:

  • getInstance():該方法用來(lái)獲取當(dāng)前處理器的實(shí)例
  • setProcessor(FilterProcessor processor):該方法用來(lái)設(shè)置處理器實(shí)例,可以使用此方法來(lái)設(shè)置自定義的處理器
  • processZuulFilter(ZuulFilter filter):該方法定義了用來(lái)執(zhí)行filter的具體邏輯,包括對(duì)請(qǐng)求上下文的設(shè)置,判斷是否應(yīng)該執(zhí)行,執(zhí)行時(shí)一些異常處理等
  • getFiltersByType(String filterType):該方法用來(lái)根據(jù)傳入的filterType獲取API網(wǎng)關(guān)中對(duì)應(yīng)類(lèi)型的過(guò)濾器,并根據(jù)這些過(guò)濾器的filterOrder從小到大排序,組織成一個(gè)列表返回
  • runFilters(String sType):該方法會(huì)根據(jù)傳入的filterType來(lái)調(diào)用getFiltersByType(String filterType)獲取排序后的過(guò)濾器列表,然后輪詢(xún)這些過(guò)濾器,并調(diào)用processZuulFilter(ZuulFilter filter)來(lái)依次執(zhí)行它們
  • preRoute():調(diào)用runFilters("pre")來(lái)執(zhí)行所有pre類(lèi)型的過(guò)濾器
  • route():調(diào)用runFilters("route")來(lái)執(zhí)行所有route類(lèi)型的過(guò)濾器
  • postRoute():調(diào)用runFilters("post")來(lái)執(zhí)行所有post類(lèi)型的過(guò)濾器
  • error():調(diào)用runFilters("error")來(lái)執(zhí)行所有error類(lèi)型的過(guò)濾器

根據(jù)我們之前的設(shè)計(jì),我們可以直接通過(guò)擴(kuò)展processZuulFilter(ZuulFilter filter)方法,當(dāng)過(guò)濾器執(zhí)行拋出異常的時(shí)候,我們捕獲它,并往請(qǐng)求上下中記錄一些信息。比如下面的具體實(shí)現(xiàn):

 
 
 
  1. public class DidiFilterProcessor extends FilterProcessor { 
  2.     @Override 
  3.     public Object processZuulFilter(ZuulFilter filter) throws ZuulException { 
  4.         try { 
  5.             return super.processZuulFilter(filter); 
  6.         } catch (ZuulException e) { 
  7.             RequestContext ctx = RequestContext.getCurrentContext(); 
  8.             ctx.set("failed.exception", e); 
  9.             ctx.set("failed.filter", filter); 
  10.             throw e; 
  11.         } 
  12.     } 

在上面代碼的實(shí)現(xiàn)中,我們創(chuàng)建了一個(gè)FilterProcessor的子類(lèi),并重寫(xiě)了processZuulFilter(ZuulFilter filter),雖然主邏輯依然使用了父類(lèi)的實(shí)現(xiàn),但是在最外層,我們?yōu)槠湓黾恿水惓2东@,并在異常處理中為請(qǐng)求上下文添加了failed.filter屬性,以存儲(chǔ)拋出異常的過(guò)濾器實(shí)例。在實(shí)現(xiàn)了這個(gè)擴(kuò)展之后,我們也就可以完善之前ErrorExtFilter中的shouldFilter()方法,通過(guò)從請(qǐng)求上下文中獲取該信息作出正確的判斷,具體實(shí)現(xiàn)如下:

 
 
 
  1. public class ErrorExtFilter extends SendErrorFilter { 
  2.     @Override 
  3.     public String filterType() { 
  4.         return "error"; 
  5.     } 
  6.     @Override 
  7.     public int filterOrder() { 
  8.         return 30; 
  9.     } 
  10.     @Override 
  11.     public boolean shouldFilter() { 
  12.         RequestContext ctx = RequestContext.getCurrentContext(); 
  13.         ZuulFilter failedFilter = (ZuulFilter) ctx.get("failed.filter"); 
  14.         if(failedFilter != null && failedFilter.filterType().equals("post")) { 
  15.             return true; 
  16.         } 
  17.         return false; 
  18.     } 

到這里,我們的優(yōu)化任務(wù)還沒(méi)有完成,因?yàn)閿U(kuò)展的過(guò)濾器處理類(lèi)并還沒(méi)有生效。***,我們需要在應(yīng)用主類(lèi)中,通過(guò)調(diào)用FilterProcessor.setProcessor(new DidiFilterProcessor());方法來(lái)啟用自定義的核心處理器以完成我們的優(yōu)化目標(biāo)。

【本文為專(zhuān)欄作者“翟永超”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)聯(lián)系作者獲取授權(quán)】

戳這里,看該作者更多好文


本文標(biāo)題:Spring Cloud實(shí)戰(zhàn)小貼士:Zuul統(tǒng)一異常處理(二)
URL鏈接:http://m.5511xx.com/article/djsosjs.html