天天看點

微服務學習第二十三節SentinelResource的fallback屬性

SentinelResource的fallback屬性

fallback屬性

概念: fallback 函數名稱,可選項,用于在抛出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了

exceptionsToIgnore

裡面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求:

  • 傳回值類型必須與原函數傳回值類型一緻;
  • 方法參數清單需要和原函數一緻,或者可以額外多一個

    Throwable

    類型的參數用于接收對應的異常。
  • fallback 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定

    fallbackClass

    為對應的類的

    Class

    對象,注意對應的函數必需為 static 函數,否則無法解析。

其實通過官網上提供的概念,我們不難看出這個屬性類似于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屬性

明顯此時顯示效果非常不好,我們就可以通過@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

    對應處理

    BlockException

    的函數名稱,可選項。blockHandler 函數通路範圍需要是

    public

    ,傳回類型需要與原方法相比對,參數類型需要和原方法相比對并且最後加一個額外的參數,類型為

    BlockException

    。blockHandler 函數預設需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定

    blockHandlerClass

    為對應的類的

    Class

    對象,注意對應的函數必需為 static 函數,否則無法解析。

案例示範

我們現在同時在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的時候,就會觸發熔斷規則。

微服務學習第二十三節SentinelResource的fallback屬性

此時我們來通路http://localhost:8084/consumer/fallback/6看效果:

  • 在沒有觸發熔斷之前的異常交給fallback來處理
微服務學習第二十三節SentinelResource的fallback屬性
  • 但是一旦觸發熔斷規則就變成了blockHandler來處理
微服務學習第二十三節SentinelResource的fallback屬性

exceptionsToIgnore屬性

  • exceptionsToIgnore

    (since 1.6.0):用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣抛出。
@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;
    }
}