Sentinel自定義異常的三種實(shí)現(xiàn)方式
Spring Cloud Alibaba Sentinel 是目前主流并開源的流量控制和系統(tǒng)保護(hù)組件,它提供了強(qiáng)大的限流、熔斷、熱點(diǎn)限流、授權(quán)限流和系統(tǒng)保護(hù)及監(jiān)控等功能。使用它可以輕松的保護(hù)我們微服務(wù),在高并發(fā)環(huán)境下的正常運(yùn)行。
那么,當(dāng)程序觸發(fā)了限流和熔斷規(guī)則時,如何自定義返回的異常信息呢?這是我們接下來要解決的問題。
0.概述
Spring Cloud Alibaba Sentinel 有以下 3 種自定義異常的實(shí)現(xiàn)方式:
- 自定義局部異常
- 自定義(Sentinel)全局異常
- 自定義系統(tǒng)異常
以上這 3 種實(shí)現(xiàn)方式,都可以重新定義 Sentinel 的異常返回信息,它們的具體實(shí)現(xiàn)如下。
1.自定義局部異常
自定義局部異常是在使用 @SentinelResource 注解時,直接定義的 blockHandler 異常方法,如下代碼所示:
@SentinelResource(value = "/user/getuser", blockHandler = "myBlockHandler") @RequestMapping("getuser") public String getUser(Integer uid) { return "User:" + uid; } /** * 定義限流/熔斷等異常 */ public String myBlockHandler(Integer uid, BlockException e) { String msg = "未知異常"; if (e instanceof FlowException) { msg = "請求被限流了"; } else if (e instanceof ParamFlowException) { msg = "請求被熱點(diǎn)參數(shù)限流"; } else if (e instanceof DegradeException) { msg = "請求被降級了"; } else if (e instanceof AuthorityException) { msg = "沒有權(quán)限訪問"; } return msg; }
注意事項(xiàng)
在定義 blockHandler 方法時,需要注意以下 3 個問題:
- 自定義的 blockHandler 方法的返回值,必須要和原方法(使用 @SentinelResource 注解修飾的方法)的返回值保持一致。
- 自定義的 blockHandler 方法的參數(shù)必須和原方法參數(shù)保持一致。
- 自定義的 blockHandler 方法的方法參數(shù)中必須包含 BlockException 參數(shù)。
如果不滿足以上事項(xiàng)中的任何一項(xiàng),那么就不能正常匹配到自定義的 blockHandler 方法,并且程序也會報錯。
2.自定義全局異常
自定義 Sentinel 全局異常需要實(shí)現(xiàn) BlockExceptionHandler 類,并重寫 handle 方法,如下代碼所示:
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; @Component public class SentinelExceptionHandler implements BlockExceptionHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception { String msg = "未知異常"; int status = HttpStatus.TOO_MANY_REQUESTS.value(); if (e instanceof FlowException) { msg = "請求被限流了"; } else if (e instanceof ParamFlowException) { msg = "請求被熱點(diǎn)參數(shù)限流"; } else if (e instanceof DegradeException) { msg = "請求被降級了"; } else if (e instanceof AuthorityException) { msg = "沒有權(quán)限訪問"; status = HttpStatus.UNAUTHORIZED.value(); } response.setContentType("application/json;charset=utf-8"); response.setStatus(status); response.getWriter().println("{\"msg\": " + msg + ", \"code\": " + status + "}"); } }
自定義 Sentinel 全局異常是在執(zhí)行 Sentinel 控制臺設(shè)置的限流和熔斷異常時,執(zhí)行的全局自定義異常方法。
但是,如果是程序中出現(xiàn)的 Sentinel 報錯信息,例如使用熱點(diǎn)限流時,因?yàn)橐浜鲜褂?@SentinelResource 注解時,此時只自定義了 value 屬性,未定義局部 blockHandler 方法,此時系統(tǒng)就會報錯,但這個時候并不會執(zhí)行 Sentinel 全局自定義異常,而是程序報錯,此時就需要使用系統(tǒng)自定義異常來重新定義異常信息了。
3.自定義系統(tǒng)異常
自定義系統(tǒng)異常需要新建一個異常類,并且使用 @RestControllerAdvice 注解修飾此類,并配合 @ExceptionHandler 注解來完成全局系統(tǒng)異常的獲取和定義,具體實(shí)現(xiàn)代碼如下:
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; import com.alibaba.csp.sentinel.slots.block.flow.FlowException; import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class CustomExceptionHandler { /** * 限流全局異常 */ @ExceptionHandler(FlowException.class) public Map handlerFlowException(){ return new HashMap(){{ put("code", HttpStatus.TOO_MANY_REQUESTS.value()); put("msg", "被限流"); }}; } /** * 熔斷全局異常 */ @ExceptionHandler(DegradeException.class) public Map handlerDegradeException(){ return new HashMap(){{ put("code", HttpStatus.TOO_MANY_REQUESTS.value()); put("msg", "被熔斷"); }}; } /** * 熱點(diǎn)限流異常 */ @ExceptionHandler(ParamFlowException.class) public Map handlerparamFlowException(){ return new HashMap(){{ put("code", HttpStatus.TOO_MANY_REQUESTS.value()); put("msg", "熱點(diǎn)限流"); }}; } /** * Sentinel 權(quán)限攔截全局異常 */ @ExceptionHandler(AuthorityException.class) @ResponseBody public Map handlerAuthorityException(){ return new HashMap(){{ put("code", HttpStatus.UNAUTHORIZED.value()); put("msg", "暫無權(quán)限"); }}; } }
此時,只要是系統(tǒng)中出現(xiàn)的 Sentinel 報錯信息,都會被此方法所捕獲,并通過自定義的代碼完成自定義異常信息的返回。
小結(jié)
Sentinel 有 3 種自定義異常的實(shí)現(xiàn):自定義局部異常、自定義(Sentinel)全局異常、自定義系統(tǒng)異常。自定義局部異常作用范圍比較小,需要給每個資源單獨(dú)設(shè)置才行;而自定義全局異常作用范圍比較大,但如果是程序報錯,也不會執(zhí)行其方法,所以需要配合系統(tǒng)異常同時來完成自定義異常的返回。
PS:如果這 3 種自定義異常同時存在,那么它的執(zhí)行優(yōu)先級是:自定義局部異常 > 自定義全局異常 > 自定義系統(tǒng)異常。
以上就是Sentinel自定義異常的三種實(shí)現(xiàn)方式的詳細(xì)內(nèi)容,更多關(guān)于Sentinel自定義異常的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解java一維數(shù)組及練習(xí)題實(shí)例
在本篇文章里小編給大家整理了關(guān)于java一維數(shù)組及練習(xí)題的相關(guān)知識點(diǎn)和實(shí)例代碼,有需要的朋友們跟著學(xué)習(xí)下。2019-07-07Java實(shí)現(xiàn)單例模式的五種方式總結(jié)
這篇文章主要介紹了如何實(shí)現(xiàn)一個單例模式,包括構(gòu)造器私有化、提供靜態(tài)私有變量和公共獲取實(shí)例接口,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-01-01Java redisson實(shí)現(xiàn)分布式鎖原理詳解
這篇文章主要介紹了Java redisson實(shí)現(xiàn)分布式鎖原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02