欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud feign服務(wù)熔斷下的異常處理操作

 更新時間:2021年06月30日 09:16:23   作者:Coder_Joker  
這篇文章主要介紹了SpringCloud feign服務(wù)熔斷下的異常處理操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

今天做項目的時候,遇到一個問題,如果我調(diào)用某個服務(wù)的接口,但是這個服務(wù)掛了,同時業(yè)務(wù)要求這個接口的結(jié)果是必須的,那我該怎么辦呢,答案是通過hystrix,但是又有一點,服務(wù)不是平白無故掛的(排除服務(wù)器停電等問題),也就是說有可能是timeout or wrong argument 等等,那么我該如何越過hystrix的同時又能將異常成功拋出呢

第一點:先總結(jié)一下異常處理的方式:

1):通過在controller中編寫@ExceptionHandler 方法

直接在controller中編寫異常處理器方法

 @RequestMapping("/test")
 public ModelAndView test()
 {
  throw new TmallBaseException();
 }
 @ExceptionHandler(TmallBaseException.class)
 public ModelAndView handleBaseException()
 {
  return new ModelAndView("error");
 }

但是呢這種方法只能在這個controller中有效,如果其他的controller也拋出了這個異常,是不會執(zhí)行的

2):全局異常處理:

@ControllerAdvice
public class AdminExceptionHandler
{
 @ExceptionHandler(TmallBaseException.class)
 public ModelAndView hAndView(Exception exception)
 {
  //logic
  return null;
 }
}

本質(zhì)是aop代理,如名字所言,全局異常處理,可以處理任意方法拋出的異常

3)通過實現(xiàn)SpringMVC的HandlerExceptionResolver接口

public static class Tt implements HandlerExceptionResolver
 { 
  @Override
  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
   Exception ex)
  {
   //logic
   return null;
  }  
 }
 

然后在mvc配置中添加即可

@Configuration
public class MyConfiguration extends WebMvcConfigurerAdapter {  
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
    //初始化異常處理器鏈
        exceptionResolvers.add(new Tt());
    } 
}

接下來就是Fegin ,如果想自定義異常需要了解1個接口:ErrorDecoder

先來看下rmi調(diào)用結(jié)束后是如果進(jìn)行decode的

Object executeAndDecode(RequestTemplate template) throws Throwable {
    Request request = targetRequest(template);
 
    //代碼省略
    try {
      if (logLevel != Logger.Level.NONE) {
        response =
            logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
        response.toBuilder().request(request).build();
      }
      if (Response.class == metadata.returnType()) {
        if (response.body() == null) {
          return response;
        }
        if (response.body().length() == null ||
                response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
          shouldClose = false;
          return response;
        }
        // Ensure the response body is disconnected
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        return response.toBuilder().body(bodyData).build();
      }
      //從此處可以發(fā)現(xiàn),如果狀態(tài)碼不再200-300,或是404的時候,意味著非正常響應(yīng)就會對內(nèi)部異常進(jìn)行解析
      if (response.status() >= 200 && response.status() < 300) {
        if (void.class == metadata.returnType()) {
          return null;
        } else {
          return decode(response);
        }
      } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
        return decode(response);
      } else {
        throw errorDecoder.decode(metadata.configKey(), response);
      }
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
      }
      throw errorReading(request, response, e);
    } finally {
      if (shouldClose) {
        ensureClosed(response.body());
      }
    }
  }

默認(rèn)的解析方式是:

 public static class Default implements ErrorDecoder { 
    private final RetryAfterDecoder retryAfterDecoder = new RetryAfterDecoder(); 
    @Override
    public Exception decode(String methodKey, Response response) {
        //獲取錯誤狀態(tài)碼,生成fegin自定義的exception
      FeignException exception = errorStatus(methodKey, response);
      Date retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER));
      if (retryAfter != null) {
        //如果重試多次失敗,則拋出相應(yīng)的exception
        return new RetryableException(exception.getMessage(), exception, retryAfter);
      }
    //否則拋出默認(rèn)的exception
      return exception;
    }

我們可以發(fā)現(xiàn),做了2件事,第一獲取狀態(tài)碼,第二重新拋出異常,額外的判斷是否存在多次失敗依然error的異常,并沒有封裝太多的異常,既然如此那我們就可以封裝我們自定義的異常了

但是注意,這塊并沒有涉及hystrix,也就意味著對異常進(jìn)行處理還是會觸發(fā)熔斷機制,具體避免方法最后講

首先我們編寫一個BaseException 用于擴(kuò)展:省略getter/setter

public class TmallBaseException extends RuntimeException
{ 
 /**
  * 
  * @author joker
  * @date 創(chuàng)建時間:2018年8月18日 下午4:46:54
  */
 private static final long serialVersionUID = -5076254306303975358L;
 // 未認(rèn)證
 public static final int UNAUTHENTICATED_EXCEPTION = 0;
 // 未授權(quán)
 public static final int FORBIDDEN_EXCEPTION = 1;
 // 超時
 public static final int TIMEOUT_EXCEPTION = 2;
 // 業(yè)務(wù)邏輯異常
 public static final int BIZ_EXCEPTION = 3;
 // 未知異常->系統(tǒng)異常
 public static final int UNKNOWN_EXCEPTION = 4;
 // 異常碼
 private int code;
 
 // 異常信息
 private String message;
 
 public TmallBaseException(int code, String message)
 {
  super(message);
  this.code = code;
  this.message = message;
 }
 
 public TmallBaseException(String message, Throwable cause)
 {
  super(message, cause);
  this.message = message;
 }
 
 public TmallBaseException(int code, String message, Throwable cause)
 {
  super(message, cause);
  this.code = code;
  this.message = message;
 }
}

OK,我們定義好了基類之后可以先進(jìn)行測試一番:服務(wù)接口controller:

//顯示某個商家合作的店鋪
 @RequestMapping(value="/store")
 public ResultDTO<Collection<BrandDTO>>findStoreOperatedBrands(@RequestParam("storeId")Long storeId)
 {
        為了測試,先直接拋出異常
  throw new TmallBaseException(TmallBaseException.BIZ_EXCEPTION, "ceshi"); 
    }

接口:

@RequestMapping(value="/auth/brand/store",method=RequestMethod.POST,produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
ResultDTO<List<BrandDTO>>findStoreOperatedBrands(@RequestParam("storeId")Long storeId);

其余的先不貼了,然后我們發(fā)起rest調(diào)用的時候發(fā)現(xiàn),拋出異常之后并沒有被異常處理器處理,這是因為我們是通過fegin,而我又配置了feign的fallback類,拋出異常的時候會自動調(diào)用這個類中的方法.

有兩種解決方法:

1.直接撤除hystrix ,很明顯its not a good idea

2.再封裝一層異常類,具體為何,如下

AbstractCommand#handleFallback 函數(shù)是處理異常的函數(shù),從方法后綴名可以得知,當(dāng)exception 是HystrixBadRequestException的時候是直接拋出的,不會觸發(fā)fallback,也就意味著不會觸發(fā)降級

final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {
            @Override
            public Observable<R> call(Throwable t) {
                circuitBreaker.markNonSuccess();
                Exception e = getExceptionFromThrowable(t);
                executionResult = executionResult.setExecutionException(e);
                if (e instanceof RejectedExecutionException) {
                    return handleThreadPoolRejectionViaFallback(e);
                } else if (t instanceof HystrixTimeoutException) {
                    return handleTimeoutViaFallback();
                } else if (t instanceof HystrixBadRequestException) {
                    return handleBadRequestByEmittingError(e);
                } else {
                    /*
                     * Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.
                     */
                    if (e instanceof HystrixBadRequestException) {
                        eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
                        return Observable.error(e);
                    }
 
                    return handleFailureViaFallback(e);
                }
            }
        };

既然如此,那一切都明了了,修改類的繼承結(jié)構(gòu)即可:

public class TmallBaseException extends HystrixBadRequestException
{
 
 /**
  * 
  * @author joker
  * @date 創(chuàng)建時間:2018年8月18日 下午4:46:54
  */
 private static final long serialVersionUID = -5076254306303975358L;
 // 未認(rèn)證
 public static final int UNAUTHENTICATED_EXCEPTION = 0;
 // 未授權(quán)
 public static final int FORBIDDEN_EXCEPTION = 1;
 // 超時
 public static final int TIMEOUT_EXCEPTION = 2;
 // 業(yè)務(wù)邏輯異常
 public static final int BIZ_EXCEPTION = 3;
 // 未知異常->系統(tǒng)異常
 public static final int UNKNOWN_EXCEPTION = 4;
 // 異常碼
 private int code;
 
 // 異常信息
 private String message;
}

至于怎么從服務(wù)器中獲取異常然后進(jìn)行轉(zhuǎn)換,就是通過上面所講的ErrorHandler:

public class TmallErrorDecoder implements ErrorDecoder 
{
 
 @Override
 public Exception decode(String methodKey, Response response)
 {
  System.out.println(methodKey);
  Exception exception=null;
  try
  {
   String json = Util.toString(response.body().asReader());
   exception=JsonUtils.json2Object(json,TmallBaseException.class);
  } catch (IOException e)
  {
   e.printStackTrace();
  }
  return exception!=null?exception:new TmallBaseException(TmallBaseException.UNKNOWN_EXCEPTION, "系統(tǒng)運行異常");
 }
}

最后微服務(wù)下的全局異常處理就ok了,當(dāng)然這個ErrorDdecoder 和BaseException推薦放在common模塊下,所有其它模塊都會使用到它。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java Builder模式實現(xiàn)原理及優(yōu)缺點解析

    Java Builder模式實現(xiàn)原理及優(yōu)缺點解析

    這篇文章主要介紹了Java Builder模式實現(xiàn)原理及優(yōu)缺點解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • Java實現(xiàn)文件批量重命名具體實例

    Java實現(xiàn)文件批量重命名具體實例

    這篇文章主要介紹了Java實現(xiàn)文件批量重命名具體實例,需要的朋友可以參考下
    2014-02-02
  • Java中l(wèi)ogback?自動刷新不生效的問題解決

    Java中l(wèi)ogback?自動刷新不生效的問題解決

    本文主要介紹了Java中l(wèi)ogback?自動刷新不生效的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 一文弄懂fastjson

    一文弄懂fastjson

    fastjson?是一個java語言編寫的高性能且功能完善的JSON庫,本文主要介紹了fastjson的使用,具有一定的參考價值,感興趣的可以了解一下
    2023-05-05
  • Java?Agent探針技術(shù)詳解示例

    Java?Agent探針技術(shù)詳解示例

    這篇文章主要介紹了Java?Agent?探針技術(shù)詳情,Java?中的?Agent?技術(shù)可以讓我們無侵入性的去進(jìn)行代理,最常用于程序調(diào)試、熱部署、性能診斷分析等場景,下文更多相關(guān)資料,感興趣的小伙伴可以參考一下
    2022-06-06
  • Java實現(xiàn)斷點續(xù)傳功能的示例代碼

    Java實現(xiàn)斷點續(xù)傳功能的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實現(xiàn)網(wǎng)絡(luò)資源的斷點續(xù)傳功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的可以了解一下
    2022-10-10
  • JSch教程使用sftp協(xié)議實現(xiàn)服務(wù)器文件載操作

    JSch教程使用sftp協(xié)議實現(xiàn)服務(wù)器文件載操作

    這篇文章主要為大家介紹了JSch如何使用sftp協(xié)議實現(xiàn)服務(wù)器文件上傳下載操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • 使用spring.profiles.active來分區(qū)配置的方法示例

    使用spring.profiles.active來分區(qū)配置的方法示例

    這篇文章主要介紹了使用spring.profiles.active來分區(qū)配置的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Java動態(tài)替換properties文件中鍵值方式

    Java動態(tài)替換properties文件中鍵值方式

    這篇文章主要介紹了Java動態(tài)替換properties文件中鍵值方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 時間處理函數(shù)工具分享(時間戳計算)

    時間處理函數(shù)工具分享(時間戳計算)

    這篇文章主要介紹了時間處理函數(shù)工具,包括得到時間戳、周一、周末、時間更改、時間精確計算等功能
    2014-01-01

最新評論