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. APACHE 安装

    APACHE  安装 到官网下载apache软件 解压apache软件 安装APR相关优化模块 创建APACHE安装目录 安装apche,开始预编译(检测安装环境) 编译和安装 启动时报错及排错 修改 ...

  2. docker学习------centos7.5下的swarm集群可视化构建

    1.swarm集群 manager : 192.168.211.175 agent1    : 192.168.211.176    agent2    :  192.168.211.177 2.环境 ...

  3. Linux ip配置

    ifconfig  查看ip ifconfig eth0  192.168.100.10  netmask 255.255.255.0  或者 ifconfig eth0  192.168.100.1 ...

  4. JavaScript之Map对象

    前言 工欲善其事,必先利其器.这是一款以前在前端项目中没有使用过的.有趣的对象,咱来看看如何使用~ 并非arrayObj.map(function) //arrayObj.map与arrayObj.f ...

  5. temp 和 tmp 文件

    TMP和TEMP文件是各种软件或系统产生的临时文件,也就是常说的垃圾文件.Windows产生的临时文件,本质上和虚拟内存没什么两样,只不过临时文件比虚拟内存更具有针对性,单独为某个程序服务而已.而它的 ...

  6. 前端node.js npm i 报错Unexpected end of JSON input while parsing near

    清缓存 npm cache clean --force 重新安装 npm install

  7. further configuration avilable 不见了

    Dynameic Web Module的further configuration avilable  不见了 打开目录下的 org.eclipse.wst.common.project.facet. ...

  8. 关于微信emoji 表情数据库存不了,或者显示为???的问题

    必须我utf8mb4,数据库就可以存 2. 数据库连接也需要是utf8mb4

  9. linux常用技能

    阿里云镜像图形界面克隆虚拟机 linux替换阿里云镜像 centos6.6安装图形界面 克隆虚拟机后网络问题 linux替换阿里云镜像 第一步:备份你的原镜像文件,以免出错后可以恢复. cp /etc ...

  10. 【interview】Microsoft面经

    ~~收集的面经~~ 1. 实现hashtable的put 和get操作 参考:https://yikun.github.io/2015/04/01/Java-HashMap%E5%B7%A5%E4%B ...