OpenFeign
官网:https://spring.io/projects/spring-cloud-openfeign/
声明式实现远程调用
OpenFeign是一个声明式客户端,它可以依据注解驱动发送负载均衡的请求
- 引入依赖
spring-cloud-starter-openfeign
- 指定远程调用服务名
@FeignClient
- 指定请求方式
@GetMapping;@PostMapping;@DeleteMapping...
- 注意,要与controller层接受请求的注解进行区分
- 指定携带数据
@RequestHeader;@RequestParam;@RequestBody
- 指定结果返回
- 响应模型
//com.atli.product.feign.ProductFeignClient
// 指定远程调用服务名为service-product
// 使用了该注解后此类中的@GetMapping之类的注解就从接收变成了发送
@FeignClient(value="service-product")
public interface ProductFeignClient{
// 向指定服务发送名为/product的GET请求,并携带路径参数id
// 返回一个Product类型的结果
@GetMapping("/product/{id}")
Product getProductById(@PathVariable("id") Long id)
}
// com.atli.product.controller.ProductController
// 调用时直接自动注入该接口,直接调用接口中方法即可(有点像mybatis的mapper接口)
@AutoWrite
ProductFeignClient productFeignClient;
productFeignClient.getProductById(1L);
日志
要开启OpenFeign的日志功能,需要在yml配置文件中对feign客户端所在包配置日志级别。再在配置类中将LoggerLevel组件注入到容器
# service-order模块application.yml
logging:
level:
com.atli.order.feign: debug
// com.atli.order.config.OrderConfig
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL
}
超时控制
当进行远程调用时,若出现某个服务长时间无响应,可能会出现服务雪崩问题(调用某个服务一直等待,请求积累过多挤占服务器资源,从而又影响更多的服务)。此时我们需要对服务调用进行超时控制来解决这一问题
默认情况下若使用了feign客户端来发送请求,那么连接请求超时为10s,资源请求超时为60s
若要修改默认超时时间可以在yml配置文件中修改
# service-product模块application.yml
spring:
cloud:
openfeign:
client:
config:
default:
logger-level: full
connect-timeout: 1000
read-timeout: 2000
service-product:
logger-level: full
connect-timeout: 3000
read-timeout: 5000
# 这里指定了默认客户端和指定客户端(service-product)的超时和日志,
# 这里的客户端就是@FeignClient(value="service-product")中的value
重试机制
当远程调用超时失败后,可以进行多次尝试。
每次的重试时间不是固定的,是按照 基础时间×时间系数重试次数基础时间\times时间系数^重试次数基础时间×时间系数重试次数来计算的
要使用重试机制,需要在配置类中将Retryer放入到容器
// com.atli.order.config.OrderConfig
@Bean
Retryer retryer(){
return new Retryer.Default();
}
拦截器
要使用openFeign的请求拦截器功能需要创建一个类来实现RequestInterceptor接口,并将其注入到IOC容器
// com.atli.order.interceptor.XTokenRequestInterceptor
// 添加一个请求拦截器
@Component
public class XTokenRequestInterceptor implements RequestInterceptor{
@Override
public void apply(RequestTemplate template){
template.header("X-Token",UUID.randomUUID().toString());
}
}
默认返回
由于服务调用具有不确定性,为了实现能让服务继续下去,需要返回一些默认数据。
要使用兜底返回功能,需要创建一个类实现ProductFeignClient接口并将其注入到ioc容器。然后再在Feign客户端的@FeignClient注解中指定此服务访问失败后需要返回的兜底类
- 要使用该功能需要整合Sentinel,使用它的熔断功能
- 引入依赖:
spring-cloud-starter-alibaba-sentinel
# service-product模块
# 开启sentinel的熔断功能
feign:
sentinel:
enabled: true
// com.atli.product.feign.fallback.ProductFeignClientFallback
// 实现兜底返回的类
@Component
public class ProductFeignClientFallback implements ProductFeignClient{
@Override
public Product getProductById(Long id){
Product product = new Product();
product.setId(id);
product.setPrice(new BigDecimal("0"));
product.setProductName("未知商品");
product.setNum(0);
return product;
}
}
// com.atli.product.feign.ProductFeignClient
// 指定兜底返回的类
@FeignClient(value="service-product",fallback=ProductFeignClientFallback.class)
public interface ProductFeignClient{
@GetMapping("/product/{id}")
Product getProductById(@PathVariable("id") Long id)
}