Feign

一、Feign概述

Feign是一个声明式的Web Service客户端。在Spring Cloud 中使用Feign,可以做到

使用HTTP请求访问远程服务,就像调用本地方法一样,同时它整合了Ribbon和Hystrix。

入门案例:

主要依赖:

    <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud OpenFeign的Starter的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>

主入口程序注解:

@SpringBootApplication
//该注解表示当程序启动时,会进行包扫描,扫描所有带@FeignClient的注解类并进行处理
@EnableFeignClients
public class SpringCloudFeignApplication { public static void main(String[] args) {
SpringApplication.run(SpringCloudFeignApplication.class, args);
}
}

config:

@Configuration
public class HelloFeignServiceConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}

FeignClient:

/**
* url = "https://api.github.com",该调用地址用于根据传入的字符串搜索github上的
* 仓库信息。HellFeignService最终会根据指定的URL和@RequestMapping对应方法,转换成最终
* 请求地址: https://api.github.com/search/repositories?q=spring-cloud-dubbo
* @FeignClient中name:指定FeignClient名称,如果项目使用了Ribbon,该名称会用户服务发现
* configuration:Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel
* fallback:定义容错处理类,当调用远程接口失败时,会调用接口的容错逻辑,fallback指定的类必须实现@FeignClient标记接口。
* fallbackFactory: 用于生成fallback类示例,可实现每个接口的通用容错逻辑,减少重复代码。
* @author Tang Jiujia
* @since 2019-03-26
*/
@FeignClient(name = "github-client", url = "https://api.github.com",
configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService { @RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
String searchRepo(@RequestParam("q") String queryStr);
}

controller:

@RestController
public class HelloFeignController { @Autowired
HelloFeignService helloFeignService; @RequestMapping(value = "/search/github")
public String searchGithubRepoByStr(@RequestParam("str") String queryStr) {
return helloFeignService.searchRepo(queryStr);
}
}

启动,浏览器输入:http://localhost:8012/search/github?str=spring-cloud-dubbo

二、Feign工作原理

主程序入口添加@EnableFeignClients注解---->定义FeignClient接口并添加@FeignClients/@FeignClient注解--->

程序启动扫描所有拥有@FeignClients/@FeignClient注解的接口并将这些信息注入Spring IOC容器--->定义的FeignClient

接口中的方法被调用---->通过JDK代理为每个接口方法生成RequestTemplate对象(该对象封装了HTTP请求需要的全部信息)

---->由RequestTemplate对象生成Request--->Request交给Client(URLConnection、Http Client等)处理--->Client被封装

到LoadBalanceClient类,这个类结合Ribbon负载均衡发起服务之间的调用。

三、Feign基础功能

1.开启GZIP压缩

Spring Cloud Feign支持对响应和请求进行GZIP压缩,以提高通信效率。

通过application.yml配置:

feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json # 配置压缩支持的MIME TYPE
min-request-size: # 配置压缩数据大小的下限
response:
enabled: true # 配置响应GZIP压缩

由于开启GZIP压缩后,Feign之间的调用通过二进制协议进行传输,返回值需要修改为ResponseEntity<byte[]>,

才可以正常显示:

@FeignClient(name = "github-client", url = "https://api.github.com", configuration = FeignGzipConfig.class)
public interface FeignClinet {
@RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
ResponseEntity<byte[]> searchRepo(@RequestParam("q") String queryStr);
}

2.开启日志

application.yml:

logging:
level:
cn.springcloud.book.feign.service.HelloFeignService: debug

配置类:

@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}

四、Feign实战应用

1.Feign默认Client的替换

Feign默认使用的是JDK原生的URLConnection发送HTTP请求,没有连接池。

1)使用HTTP Client替换默认Client

依赖:

        <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency> <dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>8.17.0</version>
</dependency>

application.yml:

server:
port:
spring:
application:
name: ch4--httpclient feign:
httpclient:
enabled: true

2.使用okhttp替换Feign默认的Client

依赖:

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

application.yml:

server:
port:
spring:
application:
name: okhttp feign:
httpclient:
enabled: false
okhttp:
enabled: true

构建自定义的OkHttpClient:

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient() {
return new okhttp3.OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool())
.build();
}
}

3.Feign的Post和Get的多参数传递

SpringMVC是支持GET方法直接绑定POJO的,但是Feign的实现并没有覆盖所有的SpringMVC功能。

最佳解决方式,通过Feign拦截器的方式处理:

1)通过实现Feign的RequestInterceptor中的apply方法进行统一拦截转换处理Feign

中的GET方法参数传递的问题。

@Component
public class FeignRequestInterceptor implements RequestInterceptor{ @Autowired
private ObjectMapper objectMapper; @Override
public void apply(RequestTemplate template) {
// feign 不支持 GET 方法传 POJO, json body转query
if (template.method().equals("GET") && template.body() != null) {
try {
JsonNode jsonNode = objectMapper.readTree(template.body());
template.body(null); HashMap<String, Collection<String>> queries = new HashMap<>();
buildQuery(jsonNode, "", queries);
template.queries(queries);
} catch (IOException e) {
e.printStackTrace();
}
}
} private void buildQuery(JsonNode jsonNode, String path,
Map<String, Collection<String>> queries) {
if (!jsonNode.isContainerNode()) {
if (jsonNode.isNull()) {
return;
}
Collection<String> values = queries.get(path);
if (null == values) {
values = new ArrayList<>();
queries.put(path, values);
}
values.add(jsonNode.asText());
return;
}
if (jsonNode.isArray()) { // 数组节点
Iterator<JsonNode> it = jsonNode.elements();
while (it.hasNext()) {
buildQuery(it.next(), path, queries);
}
} else {
Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
while (it.hasNext()) {
Map.Entry<String, JsonNode> entry = it.next();
if (StringUtils.hasText(path)) {
buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
} else { // 根节点
buildQuery(entry.getValue(), entry.getKey(), queries);
}
}
}
}
}

2)集成Swagger2用于多参数传递:

@Configuration
@EnableSwagger2
public class Swagger2Config { @Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors
.basePackage("com.demon.feign"))
.paths(PathSelectors.any()).build();
} private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Feign多参数传递问题").description("Feign多参数传递问题")
.contact("Software_King@qq.com").version("1.0").build();
}
}

3)消费者:

@RestController
@RequestMapping("/user")
public class UserController { @Autowired
private UserFeignService userFeignService; @RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser(@RequestBody @ApiParam(name="用户",
value="传入json格式",required=true) User user) {
return userFeignService.addUser(user);
} @RequestMapping(value = "/update", method = RequestMethod.POST)
public String updateUser( @RequestBody @ApiParam(name="用户",value="传入json格式",required=true) User user){
return userFeignService.updateUser(user);
}
}

4)Feign Client:

@FeignClient(name = "provider")
public interface UserFeignService { @RequestMapping(value = "/user/add", method = RequestMethod.GET)
public String addUser(User user); @RequestMapping(value = "/user/update", method = RequestMethod.POST)
public String updateUser(@RequestBody User user);
}

5)服务提供者:

@RestController
@RequestMapping("/user")
public class UserController { @RequestMapping(value = "/add", method = RequestMethod.GET)
public String addUser(User user , HttpServletRequest request){
String token=request.getHeader("oauthToken");
return "hello,"+user.getName();
} @RequestMapping(value = "/update", method = RequestMethod.POST)
public String updateUser( @RequestBody User user){
return "hello,"+user.getName();
}
}

Spring Cloud微服务笔记(五)Feign的更多相关文章

  1. spring cloud微服务实践五

    本篇我们来看看怎么实现spring cloud的配置中心. 在分布式系统中,特别是微服务架构下,可能会存在许多的服务,每个服务都会存在一个或多个的配置文件.那怎么多的配置文件的管理就会成为一个大问题. ...

  2. Spring Cloud微服务笔记(二)Spring Cloud 简介

    Spring Cloud 简介 Spring Cloud的设计理念是Integrate Everything,即充分利用现有的开源组件, 在它们之上设计一套统一的规范/接口使它们能够接入Spring ...

  3. Spring Cloud微服务笔记(三)服务治理:Spring Cloud Eureka快速入门

    服务治理:Spring Cloud Eureka 一.服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 1.服务注册: 在服务治理框架中,通常会构 ...

  4. Spring Cloud微服务笔记(一)微服务概念

    微服务概念 一.什么是微服务架构 微服务,是一个小的.松耦合的分布式服务. 为什么需要微服务: 1)单体系统部署在一个进程中,修改了一个小功能,为了部署上线就会影响其他功能. 2)单体应用各个功能模块 ...

  5. Spring Cloud 微服务笔记(六)Spring Cloud Hystrix

    Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...

  6. Spring Cloud微服务笔记(四)客户端负载均衡:Spring Cloud Ribbon

    客户端负载均衡:Spring Cloud Ribbon 一.负载均衡概念 负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容.因为负载均衡对系统的高可用性. 网络压力的缓解和处理能力的扩容的 ...

  7. Spring Cloud 微服务笔记(七) Zuul入门

    Zuul入门 Zuul是从设备和网站到后端应用程序所有请求的前门,为内部服务提供可配置的对外URL到服务的 映射关系,基于JVM的后端路由器.其具备一下功能: 1)认证与授权 2)压力控制 3)金丝雀 ...

  8. Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结

    在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...

  9. Spring Cloud微服务限流之Sentinel+Apollo生产实践

    Sentinel概述 在基于Spring Cloud构建的微服务体系中,服务之间的调用链路会随着系统的演进变得越来越长,这无疑会增加了整个系统的不可靠因素.在并发流量比较高的情况下,由于网络调用之间存 ...

随机推荐

  1. Excel表格中依据某一列的值,将这列中一样的数据放在一个文件中。

    一需求:按照标题C的内容,一样的数据整理到一个文件中. 二.操作: 1.atl+F11弹出vb窗口 2.点击       插入===>模块   ,复制以下代码,注意这是一个表头为三行的函数(保存 ...

  2. Linux下批量杀掉 包含某个关键字的 程序进程

    有时候因为一些情况,需要把 linux 下符合某一项条件的所有进程 kill 掉,又不能用 killall 直接杀掉某一进程名称包含的所有运行中进程(我们可能只需要杀掉其中的某一类或运行指定参数命令的 ...

  3. sketch格式文件转换成psd

    在做响应式页面的时间需要把px单位转换成rem才可以,但是sketch文件的格式不能随意转换成rem,最高只能到CSS rem 16px,不能满足我们的需求,因此需要一个工具来转换成psd格式文件,他 ...

  4. mitx一大堆统计学知识

    从几乎0一路讲到马克洛夫 mit的密度太高了 下次必须花3天时间准备

  5. 2018-2019-2 20175204 张湲祯 实验二《Java面向对象程序设计》实验报告

    2018-2019-2-20175204 张湲祯 实验二 <Java开发环境的熟悉>实验报告 实验二 Java面向对象程序设计 一.实验内容: 初步掌握单元测试和TDD 理解并掌握面向对象 ...

  6. 【转】Python多进程编程

    [转]Python多进程编程 序. multiprocessingpython中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程.Pytho ...

  7. 010_TCP queue的研究

    先来回顾下三次握手里面涉及到的问题:1. 当 client 通过 connect 向 server 发出 SYN 包时,client 会维护一个 socket 等待队列,而 server 会维护一个 ...

  8. VUE中/deep/深度作用域

    vue中css样式不起作用,用!important也不起作用,此时需要用 /deep/ ,没加之前是 加了之后起作用了,此时这个deep是深度作用域

  9. 如何配置adb环境变量

    如何配置adb环境变量? 1.我的电脑---控制面板---高级系统设置 2.点击[高级系统设置],弹出系统属性的弹框, 3.点击[环境变量],弹出环境变量弹框,新建一个系统变量,命名为Android ...

  10. Lesson 1-2

    1.5 模块 模块可视为扩展,通过将其导入可以扩展python的功能.python中自带有一组模块,也称为“标准库”. 1.5.1 模块的导入:import + 模块名称 • 使用关键字import导 ...