微服务与Spring CloudSpring Cloud工作专题

探讨通过Feign配合Hystrix进行调用时异常的处理

2017-06-25  本文已影响2086人  vincent_ren

前言

场景及痛点

问题解决方案分析

解决思路

对应源码解释对应方案

主要类对象简介

不使用Hystrix

源码分析

//省略部分代码
    @Configuration
    @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
    protected static class HystrixFeignConfiguration {
        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = true)
        public Feign.Builder feignHystrixBuilder() {
        return HystrixFeign.builder();
        }
    }
//省略部分代码

解决方案

  1. 配置增加 feign.hystrix.enabled=false ,这会在全局生效不推荐。
  2. FeignConfiguration 增加:(推荐)
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder() {
        return Feign.builder();
    } 

使用 Hystrix 解决内部调用抛出异常问题

源码分析

 //省略部分代码
 private Observable<R> executeCommandAndObserve(final AbstractCommand<R> _cmd) {
//省略部分代码
        final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {
            @Override
            public Observable<R> call(Throwable t) {
                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);
                }
            }
        };
//省略部分代码
    }

该类中该方法为发生异常的回调方法,由此可以看出如果抛出异常如果是 HystrixBadRequestException 是直接处理异常之后进行抛出(这里不会触发熔断机制),而不是进入回调方法。

解决方案

封装异常说明:

public class UserErrorDecoder implements ErrorDecoder{

    private Logger logger = LoggerFactory.getLogger(getClass());

    public Exception decode(String methodKey, Response response) {
        ObjectMapper om = new JiaJianJacksonObjectMapper();
        JiaJianResponse resEntity;
        Exception exception = null;
        try {
            resEntity = om.readValue(Util.toString(response.body().asReader()), JiaJianResponse.class);
//为了说明我使用的 WebApplicationException 基类,去掉了封装
            exception = new WebApplicationException(javax.ws.rs.core.Response.status(response.status()).entity(resEntity).type(MediaType.APPLICATION_JSON).build());
            // 这里只封装4开头的请求异常
            if (400 <= response.status() && response.status() < 500){
              exception = new HystrixBadRequestException("request exception wrapper", exception);
            }else{
              logger.error(exception.getMessage(), exception);
            }
        } catch (IOException ex) {
            logger.error(ex.getMessage(), ex);
        }
        return exception;
    }
}

为 Feign 配置 ErrorDecoder

@Configuration
public class FeignConfiguration {
    @Bean
    public ErrorDecoder errorDecoder(){
        return new UserErrorDecoder();
    }
}

业务系统处理异常说明:

    @Override
    public UserSigninResEntity signIn(UserSigninReqEntity param) throws Exception {
        try {
            //省略部分代码
            UserSigninResEntity entity = userRemoteCall.signin(secretConfiguration.getKeys().get("user-service"), param);
             //省略部分代码
        } catch (Exception ex) {
        
            //这里进行异常处理
            if(ex.getCause() instanceof WebApplicationException){
                ex = (WebApplicationException) ex.getCause();
            }
            logger.error(ex.getMessage(), ex);
            throw ex;
        }
    }

总结

上一篇 下一篇

猜你喜欢

热点阅读