什么是Feign

Feign是一个声明式Web Service客户端。

使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。

Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

Feign的组成

接口 作用 默认值
Feign.Builder Feign的入口 Feign.Builder
Client Feign底层用什么去请求 和Ribbon配合时:LoadBalancerFeignClient(代理模式,可以为Feign引入连接池) 不和Ribbon配合时:Fgien.Client.Default(URLConnection,没有连接池,没有资源管理,性能较差)
Contract 契约,注解支持 SpringMVCContract
Encoder 解码器,用于将独享转换成HTTP请求消息体 SpringEncoder
Decoder 编码器,将相应消息体转成对象 ResponseEntityDecoder
Logger 日志管理器 Slf4jLogger
RequestInterceptor 用于为每个请求添加通用逻辑

整合Feign

在pom.xml文件中添加依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动类上添加@EnableFeignClients注解

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import tk.mybatis.spring.annotation.MapperScan; // 扫猫Mybatis哪些包里面的接口
@MapperScan("com.example")
@SpringBootApplication
@EnableFeignClients
public class Study01Application { public static void main(String[] args) {
SpringApplication.run(Study01Application.class, args);
} @Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
} }

使用Feign实现远程http调用

创建feignClient包,用来存放Feign接口,因为我整合过程中调用的是comment接口,所以创建CommentFeignClient接口类。

添加注解@FeignClient,表明这个接口是一个FeignClient,指定name,name是要请求的微服务的名称。

这时,就可以在接口中添加方法了,方法注解参照spring mvc的注解,代码如下:

@FeignClient(name = "study02")
public interface CommentFeignClient {
@GetMapping("/find")
DemoComment find();
}

在前文中,微服务A如果要调用微服务B的请求,参考代码如下:

private final DiscoveryClient discoveryClient;
private final RestTemplate restTemplate; public DemoComment findById() {
// 获取请求示例
List<ServiceInstance> instances = discoveryClient.getInstances("study02");
List<String> collect = instances.stream()
.map(instance -> instance.getUri().toString() + "/find")
.collect(Collectors.toList());
// 随机算法
int i = ThreadLocalRandom.current().nextInt(collect.size());
String targetURL = collect.get(i);
DemoComment forObject = restTemplate.getForObject("http://study02/find", DemoComment.class, 1);
return forObject;
}

其中, DemoComment forObject = restTemplate.getForObject("http://study02/find", DemoComment.class, 1);是具体的请求代码,我们借用RestTemplate接口实现了服务间的请求调用。

那么,利用Feign又如何做到呢?

  • 首先,我们将restTemplate注入更换为刚刚添加的CommentFeignClient注入
  • 然后直接使用commentFeignClient.***()调用请求就可以了。

代码如下:

private final DiscoveryClient discoveryClient;
private final CommentFeignClient commentFeignClient; public DemoComment findById() {
DemoComment forObject = commentFeignClient.find();
return forObject;
}

Feign的配置

和Ribbon一样,Feign也支持两种配置方式:java代码方式及配置属性模式

Feign支持的配置项

代码支持的配置项

配置项 作用
Logger.Level 指定日志级别
Retryer 指定重试策略
ErrorDecoder 指定错误解码器
Request.Options 超时时间
Collection 拦截器
SetterFactory 用于设置Hystrix的配置属性,Fgien整合Hystrix才会用

属性支持的配置项

feign:
client:
config:
feignName:
connectTimeout: 5000 # 相当于Request.Optionsn 连接超时时间
readTimeout: 5000 # 相当于Request.Options 读取超时时间
loggerLevel: full # 配置Feign的日志级别,相当于代码配置方式中的Logger
errorDecoder: com.example.SimpleErrorDecoder # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
retryer: com.example.SimpleRetryer # 配置重试,相当于代码配置方式中的Retryer
requestInterceptors: # 配置拦截器,相当于代码配置方式中的RequestInterceptor
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
# 是否对404错误解码
decode404: false
encode: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
contract: com.example.SimpleContract

下面以feign的日志级别自定义为例展示feign的配置

细粒度配置

Java代码

首先,添加Feign配置类,可以添加在主类下,但是不用添加@Configuration。如果添加了@Configuration而且又放在了主类之下,那么就会所有Feign客户端实例共享,同Ribbon配置类一样父子上下文加载冲突;如果一定添加@Configuration,就放在主类加载之外的包。建议还是不用加@Configuration。

import feign.Logger;
import org.springframework.context.annotation.Bean; public class DemoFeignConfiguration {
@Bean
public Logger.Level level() {
// 让Feign打印所有请求的细节
return Logger.Level.FULL;
}
}

然后,给@FeignClient添加配置类

@FeignClient(name = "study02", configuration = DemoFeignConfiguration.class)
public interface CommentFeignClient {
@GetMapping("/find")
DemoComment find();
}

因为示例的是日志级别自定义,而feign的日志级别是建立在feign的接口的日志级别是debug的基础上的,所以需要添加配置属性

logging:
level:
#需要将FeignClient接口全路径写上
com.example.study01.feignClient.CommentFeignClient: debug

配置属性

feign:
client:
config:
#想要调用的微服务名称,不是本身
study02:
loggerLevel: FULL

全局配置

Java代码

在启动类上为@EnableFeignClients注解添加defaultConfiguration配置

@EnableFeignClients(defaultConfiguration = DemoFeignConfiguration.class)

配置属性

feign:
client:
config:
#将调用的微服务名称改成default就配置成全局的了
default:
loggerLevel: FULL

优先级:细粒度属性配置 > 细粒度代码配置 > 全局属性配置 > 全局代码配置

打印出来的信息如下:

2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient     : [CommentFeignClient#find] <--- HTTP/1.1 200 (425ms)
2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient : [CommentFeignClient#find] content-type: application/json;charset=UTF-8
2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient : [CommentFeignClient#find] date: Tue, 22 Oct 2019 06:55:41 GMT
2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient : [CommentFeignClient#find] transfer-encoding: chunked
2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient : [CommentFeignClient#find]
2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient : [CommentFeignClient#find] {"id":1,"typeId":0,"valueId":1152101,"content":"MTE=","addTime":1504933578,"status":0,"userId":15}
2019-10-22 14:55:41.286 DEBUG 31468 --- [nio-8881-exec-1] c.e.s.feignClient.CommentFeignClient : [CommentFeignClient#find] <--- END HTTP (98-byte body)
2019-10-22 14:55:42.142 INFO 31468 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: study02.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

Feign多参数请求构造

GET请求

使用@SpringQueryMap

@FeignClient(name = "study02")
public interface CommentFeignClient {
@GetMapping("/find")
public DemoComment query(@SpringQueryMap DemoComment comment);
}

使用 @RequestParam

@FeignClient(name = "study02")
public interface CommentFeignClient {
@RequestMapping(value = "/find",method = RequestMethod.GET)
public DemoComment query(@RequestParam("id") Long id, @RequestParam("name") String name);
}

使用Map构建(不推荐)

@FeignClient(name = "study02")
public interface CommentFeignClient {
@RequestMapping(value = "/find",method = RequestMethod.GET)
public DemoComment query(@RequestParam Map<String,Object> map);
}

POST请求

服务提供者方法

 @PostMapping("/save")
public DemoComment save(@RequestBody DemoComment comment){
return null;
}

服务调用者

@FeignClient(name = "study02")
public interface CommentFeignClient {
@RequestMapping(value = "/save",method = RequestMethod.POST)
public DemoComment query(@RequestBody DemoComment comment);
}

Feign性能优化

配置连接池

apache httpClient

添加依赖

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>

添加配置

feign:
httpclient:
# 让feign使用apache httpclient作请求
enabled: true
# feign的最大连接数
max-connections: 200
# feign单个路径的最大连接数
max-connections-per-route: 50

okHttp

加依赖

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>1.10<version>
</dependency>

添加配置

 httpclient:
# feign 最大连接数
max-connections: 200
# feign 单个路径请求的最大连接数
max-connections-per-route: 50
okhttp:
enabled: true

合理使用Feign日志

生产环境使用 Logger.Level.BASIC

Spring Cloud Alibaba学习笔记(4) - Feign配置与使用的更多相关文章

  1. Spring Cloud Alibaba学习笔记(1) - 整合Spring Cloud Alibaba

    Spring Cloud Alibaba从孵化器版本毕业:https://github.com/alibaba/spring-cloud-alibaba,记录一下自己学习Spring Cloud Al ...

  2. Spring Cloud Alibaba学习笔记(15) - 整合Spring Cloud Gateway

    Spring Cloud Gateway 概述 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于Netty.Reactor以及WEbFlux构建,它 ...

  3. Spring Cloud Alibaba学习笔记(3) - Ribbon

    1.手写一个客户端负载均衡器 在了解什么是Ribbon之前,首先通过代码的方式手写一个负载均衡器 RestTemplate restTemplate = new RestTemplate(); // ...

  4. Spring Cloud Alibaba学习笔记(22) - Nacos配置管理

    目前业界流行的统一配置管理中心组件有Spring Cloud Config.Spring Cloud Alibaba的Nacos及携程开源的Apollo,本文将介绍Nacos作为统一配置管理中心的使用 ...

  5. Spring Cloud Alibaba学习笔记(2) - Nacos服务发现

    1.什么是Nacos Nacos的官网对这一问题进行了详细的介绍,通俗的来说: Nacos是一个服务发现组件,同时也是一个配置服务器,它解决了两个问题: 1.服务A如何发现服务B 2.管理微服务的配置 ...

  6. Spring Cloud Alibaba学习笔记

    引自B站楠哥:https://space.bilibili.com/434617924 一.创建父工程 创建父工程hello-spring-cloud-alibaba Spring Cloud Ali ...

  7. Spring Cloud Alibaba学习笔记(23) - 调用链监控工具Spring Cloud Sleuth + Zipkin

    随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请求可能最终需要调用很多次后端服务才能完成,当整个请求陷入性能瓶颈或不可用时,我们是无法得知该请求是由某个或某些后端服务引起的,这时就需要解决如何 ...

  8. Spring Cloud Alibaba学习笔记(18) - Spring Cloud Gateway 内置的过滤器工厂

    参考:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-clou ...

  9. Spring Cloud Alibaba学习笔记(14) - Spring Cloud Stream + RocketMQ实现分布式事务

    发送消息 在Spring消息编程模型下,使用RocketMQ收发消息 一文中,发送消息使用的是RocketMQTemplate类. 在集成了Spring Cloud Stream之后,我们可以使用So ...

随机推荐

  1. Vue 中Axios 使用

    1.安装axios npm install axios 2.在使用的地方导入 import axios from 'axios' 3.再方法中调用 sendHttp: function () { ax ...

  2. 使用FCKeditor编辑器上传文件时中文文件名乱码

    修改:editor\filemanager\browser\default\frmupload.html 文件的编码改为UTF-8 实在不行:fckeditor/editor/filemanager/ ...

  3. java和c# md5加密

    MD5加密的方式有很多,加盐的方式更多,最近项目需要java和c#加密结果一致,形成方法如下: 1.c#加密方法/// <summary> /// MD5 加密字符串 /// </s ...

  4. C++main函数命令行选项——学习笔记

    atoi字符串的数转化为整数 atof转化为小数

  5. script 命令/方法/函数

    $redis->script('load', $script); $redis->script('flush'); $redis->script('kill'); $redis-&g ...

  6. istio 简介

    最近接触到了 istio,感觉十分强大,写篇短文推荐给大家.本文所涉及的具体实验步骤可以参考官网教程. istio 相关文章列表: istio 简介 istio 性能测试 istio 是什么 Isti ...

  7. Web.Config中配置字符串含引号的处理

    配置文件中往往要用到一些特殊的字符, Web.Config默认编码格式为UTF-8,对于XML文件,要用到实体转义码来替换.对应关系如下: 字符 转义码 & 符号 & & 单引 ...

  8. 基于ADO的远程Oracle连接

    最近在一个通过MFC做一个界面,通过这个界面可以对布置在另一台服务器上的数据库MySQL.SQl Server.Oracle进行增删创建表的操作.其中我通过ADO很快就完成了对MySQL和SQL Se ...

  9. vue-cli4.0 基于 antd-design-vue 二次封装发布到 npm 仓库

    1. 安装 cli npm install -g @vue/cli vue create winyh-ui 2.安装 antd-design-vue cnpm i ant-design-vue --s ...

  10. 单机prometheus vs 集群kube-prometheus+prometheus-operator

    prometheus 组件: node-exporter:9100端口 https://segmentfault.com/a/1190000017959127