### Feign常见问题总结
**FeignClient接口如使用`@PathVariable` ,必须指定value属性**
```java
//在一些早期版本中, @PathVariable("id") 中的 "id" ,也就是value属性,必须指定,不能省略。
@FeignClient("microservice-provider-user")
public interface UserFeignClient {
@RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
...
}
```
**Java代码自定义Feign Client的注意点与坑**
```java
@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的配置!!!

**@FeignClient 注解属性**
```java
//@FeignClient(name = "microservice-provider-user")
//在早期的Spring Cloud版本中,无需提供name属性,从Brixton版开始,@FeignClient必须提供name属性,否则应用将无法正常启动!
//另外,name、url等属性支持占位符。例如:
@FeignClient(name = "${feign.name}", url = "${feign.url}")
```
**类级别的@RequestMapping会被Spring MVC加载**
```java
@RequestMapping("/users")
@FeignClient(name = "microservice-user")
public class TestFeignClient {
// ...
}
```
类上的`@RequestMapping` 注解也会被Spring MVC加载。该问题现已经被解决,早期的版本有两种解决方案:
**方案1:**不在类上加@RequestMapping 注解;
**方案2:**添加如下代码:
```java
@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();
}
}
}
```
**首次请求失败**
Ribbon的饥饿加载(eager-load)模式

**如需产生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的监控。如何添加监控支持呢?需要以下几步:

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

org.springframework.cloud
spring-cloud-starter-hystrix

```
第二步:在启动类上添加@EnableCircuitBreaker 注解,示例:
```java
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
@EnableCircuitBreaker
public class MovieFeignHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(MovieFeignHystrixApplication.class, args);
}
}
```
第三步:在application.yml中添加如下内容,暴露hystrix.stream端点:
```yml
management:
endpoints:
web:
exposure:
include: 'hystrix.stream'
```
这样,访问任意Feign Client接口的API后,再访问http://IP:PORT/actuator/hystrix.stream ,就会展示一大堆Hystrix监控数据了。

原文链接:http://www.itmuch.com/spring-cloud-sum/feign-problems/

#### Feign 上传文件
**加依赖**
```pom

io.github.openfeign.form
feign-form
3.0.3

io.github.openfeign.form
feign-form-spring
3.0.3

```
**编写Feign Client**
```java
@FeignClient(name = "ms-content-sample", configuration = UploadFeignClient.MultipartSupportConfig.class)
public interface UploadFeignClient {
@RequestMapping(value = "/upload", method = RequestMethod.POST,
produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseBody
String handleFileUpload(@RequestPart(value = "file") MultipartFile file);

class MultipartSupportConfig {
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
}
```
如代码所示,在这个Feign Client中,我们引用了配置类`MultipartSupportConfig` ,在`MultipartSupportConfig` 中,我们实例化了`SpringFormEncoder` 。这样这个Feign Client就能够上传啦。
**注意点**
-
```java
//RequestMapping注解中的produeces 、consumes 不能少;
@RequestMapping(value = "/upload", method = RequestMethod.POST,
produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
```
- 接口定义中的注解`@RequestPart(value = "file")` 不能写成`@RequestParam(value = "file")` 。
- 最好将Hystrix的超时时间设长一点,例如5秒,否则可能文件还没上传完,Hystrix就超时了,从而导致客户端侧的报错。

原文链接:http://www.itmuch.com/spring-cloud-sum/spring-cloud-feign-upload/

#### Feign实现Form表单提交
**添加依赖:**
```pom

io.github.openfeign.form
feign-form
3.2.2

io.github.openfeign.form
feign-form-spring
3.2.2

```
**Feign Client示例:**
```java
@FeignClient(name = "xxx", url = "http://www.itmuch.com/", configuration = TestFeignClient.FormSupportConfig.class)
public interface TestFeignClient {
@PostMapping(value = "/test",
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE},
produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
)
void post(Map queryParam);

class FormSupportConfig {
@Autowired
private ObjectFactory messageConverters;
// new一个form编码器,实现支持form表单提交
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
// 开启Feign的日志
@Bean
public Logger.Level logger() {
return Logger.Level.FULL;
}
}
}
```
**调用示例:**
```java
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
HashMap param = Maps.newHashMap();
param.put("username","zhangsan");
param.put("password","pwd");
this.testFeignClient.post(param);
return new User();
}
```
**日志:**
```code
...[TestFeignClient#post] ---> POST http://www.baidu.com/test HTTP/1.1
...[TestFeignClient#post] Accept: application/json;charset=UTF-8
...[TestFeignClient#post] Content-Type: application/x-www-form-urlencoded; charset=UTF-8
...[TestFeignClient#post] Content-Length: 30
...[TestFeignClient#post]
...[TestFeignClient#post] password=pwd&username=zhangsan
...[TestFeignClient#post] ---> END HTTP (30-byte body)
```
由日志可知,此时Feign已能使用Form表单方式提交数据。

原文链接:http://www.itmuch.com/spring-cloud-sum/feign-form-params/

### Feign GET请求如何构造多参数
假设需请求的URL包含多个参数,例如http://microservice-provider-user/get?id=1&username=张三 ,该如何使用Feign构造呢?
我们知道,Spring Cloud为Feign添加了Spring MVC的注解支持,那么我们不妨按照Spring MVC的写法尝试一下:
```java
@FeignClient("microservice-provider-user")
public interface UserFeignClient {
@RequestMapping(value = "/get", method = RequestMethod.GET)
public User get0(User user);
}
```
然而,这种写法并不正确,控制台会输出类似如下的异常。
```code
feign.FeignException: status 405 reading UserFeignClient#get0(User); content:
{"timestamp":1482676142940,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/get"}
```
由异常可知,尽管我们指定了GET方法,Feign依然会使用POST方法发送请求。于是导致了异常。正确写法如下

**方法一[推荐]**
**注意:使用该方法无法使用Fegin的继承模式**
```java
@FeignClient("microservice-provider-user")
public interface UserFeignClient {
@GetMapping("/get")
public User get0(@SpringQueryMap User user);
}
```
**方法二[推荐]**
```java
@FeignClient(name = "microservice-provider-user")
public interface UserFeignClient {
@RequestMapping(value = "/get", method = RequestMethod.GET)
public User get1(@RequestParam("id") Long id, @RequestParam("username") String username);
}
```
这是最为直观的方式,URL有几个参数,Feign接口中的方法就有几个参数。使用@RequestParam注解指定请求的参数是什么。

**方法三[不推荐]**
多参数的URL也可使用Map来构建。当目标URL参数非常多的时候,可使用这种方式简化Feign接口的编写。
```java
@FeignClient(name = "microservice-provider-user")
public interface UserFeignClient {
@RequestMapping(value = "/get", method = RequestMethod.GET)
public User get2(@RequestParam Map map);
}
```
在调用时,可使用类似以下的代码。
```java
public User get(String username, String password) {
HashMap map = Maps.newHashMap();
map.put("id", "1");
map.put("username", "张三");
return this.userFeignClient.get2(map);
}
```
**注意:**这种方式不建议使用。主要是因为可读性不好,而且如果参数为空的时候会有一些问题,例如`map.put("username", null);` 会导致服务调用方(消费者服务)接收到的username是"" ,而不是null。

原文链接:http://www.itmuch.com/spring-cloud-sum/feign-multiple-params-2/

### 切换为 Okhttp3 提升 QPS 性能优化
**加依赖引入okhttp3**
```pom

io.github.openfeign
feign-okhttp
${version}

```
**写配置**
```yml
feign:
# feign启用hystrix,才能熔断、降级
# hystrix:
# enabled: true
# 启用 okhttp 关闭默认 httpclient
httpclient:
enabled: false #关闭httpclient
# 配置连接池
max-connections: 200 #feign的最大连接数
max-connections-per-route: 50 #fegin单个路径的最大连接数
okhttp:
enabled: true
# 请求与响应的压缩以提高通信效率
compression:
request:
enabled: true
min-request-size: 2048
mime-types: text/xml,application/xml,application/json
response:
enabled: true
```
**参数配置**
```java
/**
* 配置 okhttp 与连接池
* ConnectionPool 默认创建5个线程,保持5分钟长连接
*/
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class) //SpringBoot自动配置
public class OkHttpConfig {

// 默认老外留给你彩蛋中文乱码,加上它就 OK
@Bean
public Encoder encoder() {
return new FormEncoder();
}

@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
//设置连接超时
.connectTimeout(10, TimeUnit.SECONDS)
//设置读超时
.readTimeout(10, TimeUnit.SECONDS)
//设置写超时
.writeTimeout(10, TimeUnit.SECONDS)
//是否自动重连
.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool(10, 5L, TimeUnit.MINUTES))
.build();
}
}
```
原文链接:https://mp.weixin.qq.com/s/PAjXS9d6Sxa04pw1Lw2HXQ

[赵小胖个人博客](https://zc.happyloves.cn:4443/wordpress/)

Spring Cloud Feign 总结问题,注意点,性能调优,切换okhttp3的更多相关文章

  1. 笔记:Spring Cloud Feign 其他配置

    请求压缩 Spring Cloud Feign 支持对请求与响应进行GZIP压缩,以减少通信过程中的性能损耗,我们只需要通过下面二个参数设置,就能开启请求与响应的压缩功能,yml配置格式如下: fei ...

  2. 使用Spring Cloud Feign

    使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务 在spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就 ...

  3. Spring cloud Feign 深度学习与应用

    简介 Spring Cloud Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单.Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解 ...

  4. spring cloud微服务快速教程之(十四)spring cloud feign使用okhttp3--以及feign调用参数丢失的说明

    0-前言 spring cloud feign 默认使用httpclient,需要okhttp3的可以进行切换 当然,其实两者性能目前差别不大,差别较大的是很早之前的版本,所以,喜欢哪个自己选择: 1 ...

  5. 笔记:Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  6. 笔记:Spring Cloud Feign Hystrix 配置

    在 Spring Cloud Feign 中,除了引入了用户客户端负载均衡的 Spring Cloud Ribbon 之外,还引入了服务保护与容错的工具 Hystrix,默认情况下,Spring Cl ...

  7. 笔记:Spring Cloud Feign 声明式服务调用

    在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常会针对各个微服务自行封装一些客户端类来包装这些依赖服务的调用,Spring Cloud Feign 在此基础上做了进 ...

  8. 第六章:声明式服务调用:Spring Cloud Feign

    Spring Cloud Feign 是基于 Netflix Feign 实现的,整合了 Spring Cloud Ribbon 和 Spring Cloud Hystrix,除了提供这两者的强大功能 ...

  9. Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  10. Spring Cloud feign

    Spring Cloud feign使用 前言 环境准备 应用模块 应用程序 应用启动 feign特性 综上 1. 前言 我们在前一篇文章中讲了一些我使用过的一些http的框架 服务间通信之Http框 ...

随机推荐

  1. hdu 4614 Vases and Flowers(线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4614 题意: 给你N个花瓶,编号是0  到 N - 1 ,初始状态花瓶是空的,每个花瓶最多插一朵花. ...

  2. Codeforce Round #574(Div.2)

                                                                                                        ...

  3. 每天学会一点点(map常量)

    map常用的声明方式(使用静态代码块): public final static Map map = new HashMap(); static { map.put("key1", ...

  4. Filter过滤器学习

    一.Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态 ...

  5. SSM框架学习笔记(一)

    Spring框架 Spring :是一个开源框架,起初是为解决企业应用开发的复杂性而创建的,但是现在已经不止 企业级应用开发,Spring的核心就是提供了一个轻量级的控制反转和面向切面编程. SPri ...

  6. Python中使用pip安装库时指定镜像源为豆瓣镜像源

    场景 在使用pip进行安装库时,使用默认的库会很慢,甚至有时会出现远程主机中断了一个现有连接. 怎样在使用pip install 时指定镜像源为豆瓣镜像源. 实现 pip install moviep ...

  7. 【学习笔记】第六章 python核心技术与实践--深入浅出字符串

    [第五章]思考题答案,仅供参考: 思考题1:第一种方法更快,原因就是{}不需要去调用相关的函数: 思考题2:用列表作为key在这里是不被允许的,因为列表是一个动态变化的数据结构,字典当中的key要求是 ...

  8. Java程序连接数据库

    /** * 了解: 利用 Driver 接口的 connect 方法获取连接 */ // 第一种实现 /** * 了解: 利用 Driver 接口的 connect 方法获取连接 */ @Test p ...

  9. airflow的安装

    1.环境准备1.1 安装环境1.2 创建用户2.安装airflow2.1 安装python2.2 安装pip2.3 安装数据库2.4 安装airflow2.4.1 安装主模块2.4.2 安装数据库模块 ...

  10. Mach-O在内存中符号表地址、字符串表地址的计算

    KSCrash 是一个用于 iOS 平台的崩溃捕捉框架,最近读了其部分源码,在 KSDynamicLinker 文件中有一个函数,代码如下: /** Get the segment base addr ...