Feign在spingcloud架构中,各微服务之间的调用工具,它整合了ribbon的负载均衡,采用声明调用,使服务之间的调用更加简单。
@FeignClient( value = "product",configuration = FeignBaseConfiguration.class)
public interface ProductClient {
@RequestMapping("/product/connect")
String connectProductService();
}
在value=xxx中配置对端服务名,将从eureka注册中心获取servername=product的微服务,根据负载均衡策略(如果是集群情况)调用product集群的微服务。
在当下的springcloud中多数引用的是openfeign:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
它是feign(已停止维护)的一层包装与功能完善:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
Feign中有两大解析器:Decoder与ErrorDecoder
Decoder用于“正向解析”(我编的),response被默认的messageConverter把内容解析成声明的返回类型。通过decoder源码可以看出当返回状态码不是404和204的情况下,将走进该解析器。也就是常见的正常状态了。此外404状态可以允许被走进该解析器如果你在feignclient中配置decode404=true
public Object decode(Response response, Type type) throws IOException {
if (response.status() != 404 && response.status() != 204) {
if (response.body() == null) {
return null;
} else {
return byte[].class.equals(type) ? Util.toByteArray(response.body().asInputStream()) : super.decode(response, type);
}
} else {
return Util.emptyValueOf(type);
}
}
ErrorDecoder:请求异常解析,对端返回的非正常状态码例如40x,50x等状态码,response将会被该解析器解析,一般如果你不重新定义解析器,它将会抛出匹配到的状态码的错误异常(FeignException)。
我们可以通过配置configuration在feignclient注解中指明来重定义这两个解析器。只需要将其定义成@Bean,feign将自动替换,当然你也可以实现该接口。
@Configuration
@Slf4j
public class FeignBaseConfiguration {
@Bean
public Decoder decoder(){
return (response, type) -> {
log.warn("response status is:{}",response.status());
return new Decoder.Default().decode(response,type);
};
}
@Bean
public ErrorDecoder errorDecoder(){
return (s, response) -> {
log.warn("response status is:{}",response.status());
return new ErrorDecoder.Default().decode(s,response);
};
}
}
重新定义后,你可以指定新的解析器来为数据进行特定的处理,例如xml格式的转换;可以抛出业务异常。在这里可以做的事情很多。
当然以上两个解析器都是在服务可达情况下,在服务不可达的情况下(服务挂了),两个解析器是没有任何反应的包括errorDecoder,他会直接抛出fegin默认的请求client(HttpClient)的异常,例如:java.net.ConnectException: Connection refused: connect
,因为这是http请求client抛出的底层异常,而不是来自feign业务。
这里就要用@ExceptionHandler进行捕获了。