SentinelResource的fallback屬性
fallback屬性
概念: fallback 函數名稱,可選項,用于在抛出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了
exceptionsToIgnore
裡面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求:
- 傳回值類型必須與原函數傳回值類型一緻;
- 方法參數清單需要和原函數一緻,或者可以額外多一個
類型的參數用于接收對應的異常。Throwable
- fallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定
為對應的類的fallbackClass
對象,注意對應的函數必需為 static 函數,否則無法解析。Class
其實通過官網上提供的概念,我們不難看出這個屬性類似于blockHandler,但是各位一定要注意他們有本質的不同。
注意: fallback屬性和blockHandler屬性的本質不同在于他們作用的異常不同:
- blockHandler:針對違反Sentinel控制台配置規則時觸發BlockException異常時對應處理的屬性
- fallback:針對Java本身出現的異常進行處理的對應屬性。
案例示範
上節課我們已經完成環境的搭建,那我們就直接在8084項目的DemoController中編寫對應代碼
首先我們先來設定異正常則
package com.mashibing.cloudalibabaconsumer8084;
import com.mashibing.cloudalibabacommons.entity.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class DemoController {
//服務提供者URL
@Value("${service-url.nacos-user-service}")
private String SERVICE_URL;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/fallback/{id}")
public JsonResult<String> fallback(@PathVariable Long id){
if(id<=3){
//通過Ribbon發起遠端通路,通路9003/9004
JsonResult<String> result = restTemplate.getForObject(SERVICE_URL+"/info/"+id,JsonResult.class);
System.err.println(result.getData());
return result;
}else{
throw new NullPointerException("沒有對應的資料記錄");
}
}
}
此時我們任務添加了異常,此時如果我們通路http://localhost:8084/consumer/fallback/4(id非法)位址時,就會出現對應的顯示效果:
明顯此時顯示效果非常不好,我們就可以通過@SentinelResource注解的fallback屬性來解決這種java異常,給出友好提示
@RestController
@Slf4j
public class DemoController {
//服務提供者URL
@Value("${service-url.nacos-user-service}")
private String SERVICE_URL;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/fallback/{id}")
//添加SentinelResource注解的fallback屬性,同時設定方法來解決Java異常
@SentinelResource(value = "falllback",fallback = "fallbackHandler")
public JsonResult<String> fallback(@PathVariable Long id){
if(id<=3){
//通過Ribbon發起遠端通路,通路9003/9004
JsonResult<String> result = restTemplate.getForObject(SERVICE_URL+"/info/"+id,JsonResult.class);
System.err.println(result.getData());
return result;
}else{
throw new NullPointerException("沒有對應的資料記錄");
}
}
//保證方法簽名基本保持一緻,但是要添加異常類型參數
public JsonResult<String> fallbackHandler(Long id,Throwable e){
JsonResult<String> result = new JsonResult<>(444,"出現未知商品id");
return result;
}
}
到這裡為止,我們就很清楚的知道了fallback屬性的作用,同時它和blockHandler屬性類似,也可以設定fallbackClass屬性,來指定對應類型,來處理對應的Java異常,當然要注意和blockHandlerClass屬性一樣,也需要讓所有的方法都必需為 static 函數,否則無法解析。
同時配置blockHandler和fallback屬性
通過上述的内容,我們很清楚的知道了fallback屬性的作用,但是大家現在想一個問題,如果我們在使用@SentinelResource屬性的時候,同時設定blockHandler屬性和fallback屬性時,并且同時出現了Sentinel異常和Java異常,這個時候會執行哪個方法那。
我們還是回顧一下blockHandler屬性的概念:
-
/blockHandler
:blockHandlerClass
對應處理blockHandler
的函數名稱,可選項。blockHandler 函數通路範圍需要是BlockException
,傳回類型需要與原方法相比對,參數類型需要和原方法相比對并且最後加一個額外的參數,類型為public
。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定BlockException
為對應的類的blockHandlerClass
對象,注意對應的函數必需為 static 函數,否則無法解析。Class
案例示範
我們現在同時在DemoController中設定fallback屬性和blockHandler屬性
@RestController
@Slf4j
public class DemoController {
//服務提供者URL
@Value("${service-url.nacos-user-service}")
private String SERVICE_URL;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/fallback/{id}")
//同時添加SentinelResource注解的fallback和blockHandler屬性
@SentinelResource(value = "falllback",fallback = "fallbackHandler",blockHandler = "blockHandler")
public JsonResult<String> fallback(@PathVariable Long id){
if(id<=3){
//通過Ribbon發起遠端通路,通路9003/9004
JsonResult<String> result = restTemplate.getForObject(SERVICE_URL+"/info/"+id,JsonResult.class);
System.err.println(result.getData());
return result;
}else{
throw new NullPointerException("沒有對應的資料記錄");
}
}
//處理Java異常
public JsonResult<String> fallbackHandler(Long id,Throwable e){
JsonResult<String> result = new JsonResult<>(444,"NullPointerException異常");
return result;
}
//處理Sentinel限流
public JsonResult<String> blockHandler(Long id, BlockException e){
JsonResult<String> result = new JsonResult<>(445,"BlockException限流");
return result;
}
}
此時我們來設定Sentinel配置,我們通過熔斷規則中的異常數來示範(當然也可以用其他的)
規則:在一秒内超過最小通路次數5次,并且異常數超過2的時候,就會觸發熔斷規則。
此時我們來通路http://localhost:8084/consumer/fallback/6看效果:
- 在沒有觸發熔斷之前的異常交給fallback來處理
- 但是一旦觸發熔斷規則就變成了blockHandler來處理
exceptionsToIgnore屬性
-
(since 1.6.0):用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣抛出。exceptionsToIgnore
@RestController
@Slf4j
public class DemoController {
//服務提供者URL
@Value("${service-url.nacos-user-service}")
private String SERVICE_URL;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/fallback/{id}")
//同時添加SentinelResource注解的fallback和blockHandler屬性
@SentinelResource(value = "falllback",fallback = "fallbackHandler",blockHandler = "blockHandler",
exceptionsToIgnore = {NullPointerException.class})//被标注的異常将會被 原樣抛出
public JsonResult<String> fallback(@PathVariable Long id){
if(id<=3){
//通過Ribbon發起遠端通路,通路9003/9004
JsonResult<String> result = restTemplate.getForObject(SERVICE_URL+"/info/"+id,JsonResult.class);
System.err.println(result.getData());
return result;
}else{
throw new NullPointerException("沒有對應的資料記錄");
}
}
//處理Java異常
public JsonResult<String> fallbackHandler(Long id,Throwable e){
JsonResult<String> result = new JsonResult<>(444,"NullPointerException異常");
return result;
}
//處理Sentinel限流
public JsonResult<String> blockHandler(Long id, BlockException e){
JsonResult<String> result = new JsonResult<>(445,"BlockException限流");
return result;
}
}