1、简介
1.1 什么是Feign
Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可帮助我们更加便捷、优雅地调用HTTP API。 Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。
Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。 它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。
1.2 Feign单独使用
引入依赖
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign‐core</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.18.0</version>
</dependency>
封装
public interface RemoteService {
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("GET /order/findOrderByUserId/{id}")
public List<Order> findOrderByUserId(@Param("id") Integer id);
@RequestLine("GET /order/queryInstanceId/")
public String queryInstanceId();
}
调用
public static void main(String[] args) {
RemoteService service = Feign.builder()
.options(new Request.Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3))
.target(RemoteService.class, "http://localhost:8011/");
System.out.println(service.queryInstanceId());
//基于json
// encoder指定对象编码方式,decoder指定对象解码方式
service = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.requestInterceptor(new MyInterceptor())
.options(new Request.Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3))
.target(RemoteService.class, "http://localhost:8011/");
System.out.println(service.findOrderByUserId(1));
}
2、 Spring Cloud 整合Feign
2.1 整合
第一步:搭建工程service-feign-api ,引入feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第二步:封装接口,添加 @FeignClient 注解
@FeignClient(name = "service-order",path = "/order")
public interface OrderApi {
@RequestMapping("/findOrderByUserId/{userId}")
public List<Order> findOrderByUserId(@PathVariable("userId") Integer userId);
}
第三步:将工程 service-feign-api 打成jar包给consumer端使用
第四步:consumer端引入 service-feign-api 依赖
<dependency>
<groupId>test.spring.cloud.com</groupId>
<artifactId>service-feign-api</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
第五步:在启动类上添加注解@EnableFeignClients
@SpringBootApplication
@EnableFeignClients(basePackages = "test.spring.cloud.com")
public class FeignconsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignconsumerApplication.class, args);
}
}
第六步:直接使用OrderApi调用接口方法
@Autowired
private OrderApi orderApi;
@RequestMapping("/getById/{id}")
public UserInfoVo getUserById(@PathVariable("id") Integer id) {
List<Order> orderList = orderApi.findOrderByUserId(id);
UserInfoVo userInfoVo = new UserInfoVo();
return userInfoVo;
}
注意:接口调用时可能会出现超时异常,SocketTimeoutException: Read timed out
进行超时时间设置:
# ribbon全局超时时间设置
ribbon.ReadTimeout=5000
ribbon.ConnectTimeout=3000
2.2 设置feign的日志级别
- NONE【性能佳,适用于生产】:不记录任何日志(默认值)。
- BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
- HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
- FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、 body和元数据。
方式一:设置配置文件
必须配置logging.level ,同时和Ribbon一样,配置类不能被主启动类 @ComponetScan扫描到
#设置Fegin接口的日志级别(接口类)
logging.level.test.spring.cloud.com.feignapi.api.OrderApi = debug
#设置Fegin接口的日志级别(包)
#logging.level.test.spring.cloud.com.feignapi.api = debug
#设置要调用微服务的日志级别 : NONE,BASIC, HEADERS,FULL
#feign.client.config.service-order.loggerLevel=full
方式二:自定义bean
在Feign接口注解上面配置configuration
@FeignClient(name = "service-order",path = "/order",configuration = FooConfiguration.class)
public interface OrderApi {
@RequestMapping("/findOrderByUserId/{userId}")
public List<Order> findOrderByUserId(@PathVariable("userId") Integer userId);
}
注册bean设置日志级别
@Configuration
public class FooConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
//设置日志级别: NONE,BASIC, HEADERS,FULL
return Logger.Level.FULL;
}
}
2.3 Feign注解替换
Feign 默认使用的是Spring Mvc 注解,可以通过配置feign.Contract.Default替换 SpringMvcContract 。
注意:如果使用@RequestLine 不配置 Contract.Default契约启动会抛异常。
在Feign接口注解上面配置configuration
@FeignClient(name="service-feign-provider",
configuration = ProviderConfig.class,path="/order")
public interface MyOrderFeignApi {
@RequestLine("GET /findOrderByUserId/{userId}")
public List<Order> findOrderByUserId(@Param("userId") Integer userId);
}
注册bean
@Configuration
public class ProviderConfig {
@Bean
public Contract feignContract() {
//使用feign自带契约
return new Contract.Default();
}
@Bean
public Logger.Level feignLoggerLevel() {
//设置日志级别: NONE,BASIC, HEADERS,FULL
return Logger.Level.FULL;
}
2.4 配置拦截器
编写拦截器,实现RequestInterceptor接口
public class MyInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
System.out.println("========执行拦截器apply=========");
requestTemplate.header("token","123456");
}
}
方式一:注册bean
@Bean
public RequestInterceptor myInterceptor() {
return new MyInterceptor();
}
方式二:consumer端设置配置文件
#配置拦截器
feign.client.config.service-feign-provider.requestInterceptors[0]=\
test.spring.cloud.com.feignapi.interceptor.MyInterceptor