feign注册
spring加载的时候通过@EnableFeignClients的FeignClientsRegistrar注册扫描所以得FeignClient以及Configuration,最终注册为ReflectiveFeign,最终通过代理类FeignInvocationHandler实现方法的调用,在
FeignInvocationHandler中通过SynchronousMethodHandler方法执行实际逻辑
当调用Feignclient里面的方法的时候最终会知道SynchronousMethodHandler的invoke方法
这里主要总结下feign的失败重试逻辑与异常捕获情况
feign异常
在SynchronousMethodHandler方法中会首先调用executeAndDecode方法,可以看到调用client.execute请求方法之后如果调用失败了则会执行errorExecuting直接返回RetryableException,
还有一个重要的方法是asyncResponseHandler.handleResponse,到这一步表示HTTP请求成功了,这里面将会根据响应码以及FeignClient中的方法返回类型反序列化来处理响应结果
首先判断是否为内定的Response类型,如果不是会根据项目配置的Decoder,可以根据自己需要配置fastjson或者jackjson以及其他的序列号工具
@Bean
public Decoder feignDecoder() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.add(MediaType.ALL);
converter.setSupportedMediaTypes(supportedMediaTypes);
ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(converter);
return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
}
如果是其他响应码会直接调用ErrorDecoder接口的decode()方法,默认的errorDecoder为ErrorDecoder.Default,默认返回FeignExcpetion,如果响应头当中含有Retry-After,则会返回RetryableException异常信息,进行后续逻辑来判断是否需要重试,但是这个默认的比较鸡肋,需要响应端提前在响应头加这个字段,调用第三方的接口时无法完成。
所以可以自己定义ErrorDecoder实现定制化的功能,比如只有当响应码为500的时候返回RetryableException后续进行重试
@Bean
public ErrorDecoder errorDecoder() {
return (methodKey, response) -> {
FeignException exception = errorStatus(methodKey, response);
if (response.status() >= 500 && response.status() <= 599) {
exception = new RetryableException(
response.status(),
exception.getMessage(),
response.request().httpMethod(),
exception,
null,
response.request());
}
return exception;
};
}
也可以自己根据响应码指定异常信息:
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String methodKey, Response response) {
int status = response.status();
switch (status) {
case 400:
return new CustomFeignException(status, "Bad Request");
case 401:
return new CustomFeignException(status, "Unauthorized");
case 403:
return new CustomFeignException(status, "Forbidden");
case 404:
return new CustomFeignException(status, "Not Found");
case 500:
return new CustomFeignException(status, "Internal Server Error");
default:
return new Exception(response.reason());
}
}
}
feign重试
如果前面步骤返回了RetryableException,则会调用Rtryer的continueOrPropagate方法,
默认为不重试,Reteyer里面内部类定义了一个Default重试方法,通过最大次数以及重试间隔来让线程休眠一段时间达到重试,在这期间调用FeignClient的线程一直处于阻塞中,所以重试不能间隔太长时间,这期间如果服务重启重试的线程则会直接断掉,所以如果不是页面操作调用接口的可以直接异步线程调用FeignClient的方法,或者自定义重试逻辑,存入延迟队列或者借助mq来处理调用失败的接口,
@Bean
public Retryer retryer() {
return new CustomRetryer(3, 1000); // 最多重试3次,每次间隔1秒
}
标签:status,Feign,调用,return,捕获,重试,new,response From: https://www.cnblogs.com/LiuFqiang/p/18516296ErrorDecode只有在请求成功的时候才会调用,如果连接超时或者网络错误,直接会抛出RetryableException,不会调用decode,所以不适合做全局异常处理