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

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

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

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

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

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

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

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

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

2):全局異常處理:

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

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

3)通過實(shí)現(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個(gè)接口: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的時(shí)候,意味著非正常響應(yīng)就會(huì)對(duì)內(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) {
        //獲取錯(cuò)誤狀態(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,也就意味著對(duì)異常進(jìn)行處理還是會(huì)觸發(fā)熔斷機(jī)制,具體避免方法最后講

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

public class TmallBaseException extends RuntimeException
{ 
 /**
  * 
  * @author joker
  * @date 創(chuàng)建時(shí)間: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;
 // 超時(shí)
 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)行測(cè)試一番:服務(wù)接口controller:

//顯示某個(gè)商家合作的店鋪
 @RequestMapping(value="/store")
 public ResultDTO<Collection<BrandDTO>>findStoreOperatedBrands(@RequestParam("storeId")Long storeId)
 {
        為了測(cè)試,先直接拋出異常
  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)用的時(shí)候發(fā)現(xiàn),拋出異常之后并沒有被異常處理器處理,這是因?yàn)槲覀兪峭ㄟ^fegin,而我又配置了feign的fallback類,拋出異常的時(shí)候會(huì)自動(dòng)調(diào)用這個(gè)類中的方法.

有兩種解決方法:

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

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

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

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)建時(shí)間: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;
 // 超時(shí)
 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)運(yùn)行異常");
 }
}

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

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

相關(guān)文章

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

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

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

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

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

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

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

    一文弄懂fastjson

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評(píng)論