本文由 简悦 SimpRead 转码, 原文地址 www.imooc.com

TIPS 本文基于 Spring Clou Greenwich SR1,理论支持 Spring Cloud Finchley 及更高版本。 本文总结 Feign 常见问题及解决方案。 一、使

TIPS

本文基于 Spring Clou Greenwich SR1,理论支持 Spring Cloud Finchley 及更高版本。

本文总结 Feign 常见问题及解决方案。

一、使用案例

二、FeignClient 接口如使用@PathVariable ,必须指定 value 属性

代码示例:

1
2
3
4
5
6
@FeignClient("microservice-provider-user")
public interface UserFeignClient {
@RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
...
}

在一些早期版本中,其中的@PathVariable("id") 中的 “id”,也就是 value 属性,必须指定,不能省略。

三、Java 代码自定义 Feign Client 的注意点与坑

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@FeignClient(name = "microservice-provider-user", configuration = UserFeignConfig.class)
public interface UserFeignClient {
@GetMapping("/users/{id}")
User findById(@PathVariable("id") Long id);
}

/**
* 该Feign Client的配置类,注意:
* 1. 该类可以独立出去;
* 2. 该类上也可添加@Configuration声明是一个配置类;
* 配置类上也可添加@Configuration注解,声明这是一个配置类;
* 但此时千万别将该放置在主应用程序上下文@ComponentScan所扫描的包中,
* 否则,该配置将会被所有Feign Client共享,无法实现细粒度配置!
* 个人建议:像我一样,不加@Configuration注解
*
* @author zhouli
*/
class UserFeignConfig {
@Bean
public Logger.Level logger() {
return Logger.Level.FULL;
}
}
  • 配置类上也可添加@Configuraiton 注解,声明这是一个配置类;但此时千万别将该放置在主应用程序上下文@ComponentScan 所扫描的包中,否则,该配置将会被所有 Feign Client 共享(相当于变成了通用配置,其实本质还是 Spring 父子上下文扫描包重叠导致的问题),无法实现细粒度配置!
  • 个人建议:像我一样,不加 @Configuration 注解,省得进坑。
  • 最佳实践:尽量用配置属性自定义 Feign 的配置!!!详见:跟我学 Spring Cloud(Finchley 版)-10-Feign 深入

四、@FeignClient 注解属性

1
@FeignClient(name = "microservice-provider-user")

在早期的 Spring Cloud 版本中,无需提供 name 属性,从 Brixton 版开始,@FeignClient 必须提供 name 属性,否则应用将无法正常启动!

另外,name、url 等属性支持占位符。例如:

1
@FeignClient(name = "${feign.name}", url = "${feign.url}")

五、类级别的 @RequestMapping 会被 Spring MVC 加载

1
2
3
4
5
@RequestMapping("/users")
@FeignClient(name = "microservice-user")
public class TestFeignClient {
// ...
}

类上的@RequestMapping 注解也会被 Spring MVC 加载。该问题现已经被解决,早期的版本有两种解决方案:

方案 1:不在类上加@RequestMapping 注解;

方案 2:添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
@ConditionalOnClass({ Feign.class })
public class FeignMappingDefaultConfiguration {
@Bean
public WebMvcRegistrations feignWebRegistrations() {
return new WebMvcRegistrationsAdapter() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new FeignFilterRequestMappingHandlerMapping();
}
};
}

private static class FeignFilterRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) && !beanType.isInterface();
}
}
}

相关 Issue:https://github.com/spring-cloud/spring-cloud-netflix/issues/466

六、首次请求失败

详见:Spring Cloud 中,如何解决 Feign/Ribbon 第一次请求失败的问题?

七、如需产生 Hystrix Stream 监控信息,需要做一些额外操作

Feign 本身已经整合了 Hystrix,可直接使用@FeignClient(value = "microservice-provider-user", fallback = XXX.class) 来指定 fallback 类,fallback 类继承 @FeignClient 所标注的接口即可。

但是假设如需使用 Hystrix Stream 进行监控,默认情况下,访问http://IP:PORT/actuator/hystrix.stream 是会返回 404,这是因为 Feign 虽然整合了 Hystrix,但并没有整合 Hystrix 的监控。如何添加监控支持呢?需要以下几步:

第一步:添加依赖,示例:

1
2
3
4
5
<!-- 整合hystrix,其实feign中自带了hystrix,引入该依赖主要是为了使用其中的hystrix-metrics-event-stream,用于dashboard -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

第二步:在启动类上添加@EnableCircuitBreaker 注解,示例:

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
@EnableCircuitBreaker
public class MovieFeignHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(MovieFeignHystrixApplication.class, args);
}
}

第三步:在 application.yml 中添加如下内容,暴露 hystrix.stream 端点:

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: 'hystrix.stream'

这样,访问任意 Feign Client 接口的 API 后,再访问http://IP:PORT/actuator/hystrix.stream ,就会展示一大堆 Hystrix 监控数据了。