Appearance
Feign
feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自于Retrofit、JAXRS-2.0以及WebSocket。Feign可以帮助我们更加便捷、优雅的调用HTTP API
Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等
Spring Cloud OpenFeign
对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Nacos,从而使得Feign的使用更加方便
优势
feign可以做到使用http请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求,它像适Dubbo一样,consumer直接调用接口方法调用provider,而不需要通过常规的HttpClient构造请求在解析返回数据,它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发
Spring Cloud Alibaba整合OpenFeign
- order服务引入openfeign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 编写调用接口
java
package com.cloud.order.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* value:注册到nacos的服务名称
* path:路径的前缀
*/
@FeignClient(value = "alibaba-stock", path = "/stock")
public interface StockFeignService {
@GetMapping("/openFeign/{goodsId}")
String openFeign(@PathVariable("goodsId") int goodsId);
}
- order服务控制层测试feign接口
java
@Autowired
private StockFeignService stockFeignService;
/**
* 测试open调用
* @param goodsId
* @return
*/
@GetMapping("openFeign/{goodsId}")
public String openFeign(@PathVariable("goodsId") int goodsId) {
String returnMsg = stockFeignService.openFeign(goodsId);
System.out.println("stock=>restTemplateGet=>"+goodsId);
return "stock=>restTemplateGet=>"+goodsId ;
}
- stock服务开放feign测试接口
java
/**
* 测试open调用
* @param goodsId
* @return
*/
@GetMapping("openFeign/{goodsId}")
public String openFeign(@PathVariable("goodsId") int goodsId) {
System.out.println("stock=>restTemplateGet=>"+goodsId);
return "stock=>restTemplateGet=>"+goodsId ;
}
- order服务启动类增加启动feign客户端功能注解
java
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
- 接口测试
访问:http://localhost:9501/order/openFeign/100
Spring Cloud Feign自定义配置及使用
日志配置
- 定义一个配置类,指定日志级别
java
package com.cloud.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 全局配置:当使用@Configuration会将配置作用所有的服务提供方
* 局部配置:如果只想针对某一个服务进行配置,就不要加@Configurat
*/
//@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
日志级别
- NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
- BASIC【适用生产环境追踪问题】:仅记录请求方法,URL、响应状态代码以及执行时间
- HEADERS:记录BASIC级别的基础上,记录请求和响应的header
- FULL【比较适用于开发及测试环境的定位问题】:记录请求和响应的header、body和元数据
- 局部配置,让调用微服务生效,在@FeignClient注解中指定使用的配置类【注意:这个配置类,不能加@Configuration,否则全局生效】
java
package com.cloud.order.feign;
import com.cloud.config.FeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* value:注册到nacos的服务名称
* path:路径的前缀
*/
@FeignClient(value = "alibaba-stock", path = "/stock", configuration = FeignConfig.class)
public interface StockFeignService {
@GetMapping("/openFeign/{goodsId}")
String openFeign(@PathVariable("goodsId") int goodsId);
}
- yml配置指定@FeignClient使用的日志级别
- 因为feign调试日志是debug级别输出,springboot默认的日志级别是info,所以feign的debug日志级别就不会输出
- logging.level=debug这样配置是对所有的日志级别进行配置
- 该场景只需要对feign接口进行debug配置,所以是这样配置logging.level.com.cloud.order.feign=debug
yaml
logging:
level:
com.cloud.order.feign: debug
补充:局部配置可以在yml中配置
对应的属性配置类:org.springframework.cloud.openfeign.FeignClientProperties.FeignClientConfiguration
yaml
feign:
client:
config:
# default是全局所有模块
alibaba-stock:
loggerLevel: FULL
自定义拦截器实现认证逻辑
- 自定义拦截器类
java
package com.cloud.interceptor;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import java.util.UUID;
public class FeignAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
// 业务逻辑
String access_token = UUID.randomUUID().toString();
requestTemplate.header("Authorization",access_token);
}
}
- 拦截器配置,增加FeignAuthRequestInterceptor类【方式一】
- yml配置拦截器【方式二】
yaml
feign:
client:
config:
alibaba-stock:
loggerLevel: FULL
requestInterceptors[0]: com.cloud.interceptor.FeignAuthRequestInterceptor
- 被调用方可以使用@RequestHeader注解获取请求头数据
java
/**
* 测试open调用
* @param goodsId
* @return
*/
@GetMapping("openFeign/{goodsId}")
public String openFeign(@PathVariable("goodsId") int goodsId, @RequestHeader("Authorization") String authorization) {
System.out.println("stock=>restTemplateGet=>"+goodsId);
return "stock=>restTemplateGet=>"+goodsId ;
}
超时时间配置
通过 Options 可以配置连接超时时间和读取超时时间,Options 的第一个参数是连接的超时时间(ms),默认值是 2s;第二个是请求处理的超时时间(ms),默认值是 5s。
客户端组件配置
Feign 中默认使用 JDK 原生的 URLConnection 发送 HTTP 请求,我们可以集成别的组件来替换掉 URLConnection,比如 Apache HttpClient,OkHttp。
Feign发起调用真正执行逻辑:feign.Client#execute
GZIP压缩配置
开启压缩可以有效节约网络资源,提升接口性能,我们可以配置 GZIP 来压缩数据