OpenFeign使用
Feign和OpenFeign
Feign是Netflix开发的⼀个轻量级RESTful的HTTP服务客户端,可以使用⽤它来发起请求,进行远程调用。Fegin是以Java接口注解的⽅式调⽤Http请求,而不是像RestTemplate那样,在Java中通过封装HTTP请求报⽂的⽅式直接调用。
Feign可帮助我们更加便捷,优雅的调⽤HTTP API:不需要我们去拼接url然后调⽤restTemplate的api,但是Fegin的缺点缺点,它不支持SpringMVC的注解。
Spring Cloud在Feign的基础上进行了封装,从而有了OpenFeign。
Feign githup主页
OpenFeign的使用
OpenFeign的使用非常简单,只需要在服务调用方创建远程调用接口,然后创建和被调用方方法一样的方法,最后在需要使用的地方导入远程调用接口,调用接口的方法即可发起请求了。
在pom文件中添加OpenFeign的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在调用方服务的启动类上添加@EnableFeignClients注解
@SpringBootApplication
@EnableFeignClients //开启Feign的功能
public class Conuserservice01Application {
public static void main(String[] args) {
try {
SpringApplication.run(Conuserservice01Application.class, args);
} catch (Exception e) {
System.out.println("e.getMessage() = " + e.getMessage());
}
}
}
创建远程调用接口
@FeignClient("providerservice") //指定要调用的服务需要和被调用的服务的application.name保持一致
public interface ProviderServiceClient {
//要调用的服务中的请求,需要被调用的服务中的请求方法保持一致
@GetMapping("/user/{userId}")
public String getUserById(@PathVariable("userId") String userId);
}
在Controller中使用远程调用接口
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private ProviderServiceClient client;
@RequestMapping("/{userId}")
public String getUserById(@PathVariable String userId) {
LOGGER.info("userId: " + userId);
String user = client.getUserById(userId);
return user;
}
}
访问/consumer/1的请求,会远程调用providerservice服务实例中请求路径为/user/{userId}的请求。
providerservice服务中被访问的请求,这个请求的方法要和远程调用接口中的方法保持一致。
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@GetMapping("/{userId}")
public String getUserById(@PathVariable String userId) {
LOGGER.info("userId: " + userId);
return "user1";
}
}
Feign的相关配置
Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:
一般我们只需要修改日志级别即可。
日志级别
Feign的日志级别有如下几种:
- NONE:默认的,不显示任何⽇志,性能最好;
- BASIC:仅记录请求⽅法、URL、响应状态码以及执⾏时间----⽣产问题追踪;
- HEADERS:在BASIC级别的基础上,记录请求和响应的header;
- FULL:记录请求和响应的header、body和元数据,适⽤于开发及测试环境定位问题;
覆盖Feign默认的配置有两个维度,一个是为每个FeignClient单独配置(局部配置),另一个是全局配置;下面先来看局部配置。不过要先在yml中设置SpringBoot的日志输出级别
logging:
level:
# Feign⽇志只会对⽇志级别为debug的做出响应,这里需要设置SpingBoot的日志级别为debug,否则不会输出feign的日志;因为springBoot日志级别默认为info,这里把ProviderServiceClient接口的日志级别设置为了debug,也可以设置指定目录的日志级别
com.example.conuserservice01.client.ProviderServiceClient: debug
局部配置日志级别
在application.yml文件中配置日志级别
logging:
level:
# ProviderServiceClient接口的方法的日志级别为debug,其它接口的不会生效
com.example.conuserservice01.client.ProviderServiceClient: debug
通过@FeignClient注解的configuration属性指定日志配置
@FeignClient(value = "providerservice", contextId = "providerservice", configuration = FeignConfig.class) //指定要调用的服务
public interface ProviderServiceClient {
//要调用的服务中的请求,需要被调用的服务中的请求方法保持一致
@GetMapping("/user/{userId}")
public String getUserById(@PathVariable("userId") String userId);
}
日志配置类
public class FeignConfig {
@Bean
Logger.Level feignLevel() {
return Logger.Level.FULL;
}
}
全局配置日志级别
全局配置日志级别可以使用yml文件配置,也可以使用配置文件进行配置。
这里如果使用服务名称则是全局配置,如果使用contextId,则是针对指定的FeignClient接口的单独配置;
spring:
cloud:
openfeign:
client:
config:
providerservice: # 如果FeignClient注解设置了contextId这里就使用contextId如,果没有设置contextId就使用服务名称
loggerLevel: full
使用配置类
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLevel() {
return Logger.Level.FULL;
}
}
负载均衡
Cloud 2020.0.X版本开始OpenFeign底层不再使用Ribbon了。所以在配置负载均衡的时候使用之前的方式是不行的。
这里使用的注册中心是Nacos,最后走的是NacosLoadBalancer。choose方法就是根据负载均衡算法选择一个服务实例进行访问。
我们在浏览器输入地址访问,然后调用远程接口访问,会执行到SynchronousMethodHandler的invoke方法。这里面executeAndDecode方法会选择服务实例,发起请求。continueOrPropagate方法则是请求出现问题后的重试。
选择服务实例并发送请求的执行流程如下:
这里会通过choose方法拿到服务实例,最后执行的是NacosLoadBalancer中的choose方法。
到这里就完成了获取服务实例的过程。
发送请求的代码在获取到服务实例的步骤后面。
然后会执行到LoadBalancerUtils的executeWithLoadBalancerLifecycleProcessing方法,通过feignRequest的url可以看到,这个时候已经将服务名转成了根据负载均衡算法选择到的服务实例的ip和端口号
最后可以看到是通过HttpURLConnection发送的请求。
请求压缩和响应压缩
OpenFeign⽀持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。可以在yml文件中配置请求压缩和响应压缩
spring:
cloud:
openfeign:
compression:
request:
enabled: true #开启请求压缩
min-request-size: 2048 #设置触发压缩的大小下限,此处也是默认值
mime-types: text/html,application/xml,application/json #设置压缩的数据类型,此处也是默认值
response:
enabled: true #开启响应压缩
对熔断器的支持
性能优化
通过前面前面的分析可以看到OpenFeign底层使用的是HttpURLConnection发送的请求,但是它不支持连接池。因此主要是针对这一点进行优化。
OpenFeign使用Apache HttpClient客户端
加入htppClient和feign-httpclient的依赖,feign-httpclient的version要和openfeign-core的version保持一致。
<!-- 使用Apache HttpClient替换Feign原生httpURLConnection -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>12.1</version>
</dependency>
开启httpClient的支持,默认是开启的。
spring:
cloud:
openfeign:
httpclient:
enabled: true
注入Apache HttpClient
@Bean
public ApacheHttpClient getApacheHttpClient() {
return new ApacheHttpClient();
}
到这里使用Apache HttpClient的配置就完成了。
使用Apache HttpClient的原理如下:
参考
- Spring Cloud OpenFeign
- Spring Cloud OpenFeign - - - > 日志级别配置
- SpringCloud OpenFeign 全功能配置详解
- Cloud 2020.0.X版本开始OpenFeign底层不再使用Ribbon
- 源码分析及实践测试OpenFeign负载均衡
- springcloud-Feign-HttpClient连接池(提升 Feign 的并发吞吐量)
- Nacos负载均衡策略
- 怎样配置Feign使用HttpClient