1.1
Feign
概述
Feign
这篇文章主要讲述如何通过
Feign
去消费服务,以及
Feign
的实现原理的解析。
Feign
是
Netflix
开发的声明式、模板化的
HTTP
客户端,
Feign
可以帮助我们更快捷、优雅地调用
HTTP API
。
Feign
是个
HTTP
请求的轻量级客户端框架。通过 接口 + 注解的方式发起
HTTP
请求调用,面向接口编程,而不是像
Java
中通过封装
HTTP
请求报文的方式直接调用。服务消费方拿到服务提供方的接,然后像调本地接法样去调,实际发出的是远程的请求。让我们更加便捷和优雅的去调基于
HTTP
的
API
,被泛应在
Spring Cloud
的解决案中。
在前面的文章中可以发现当我们通过
RestTemplate
调用其它服务的
API
时,所需要的参数须在请求的
URL
中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。
那么有没有更好的解决方案呢?答案是确定的有,
Netflix
已经为我们提供了一个框架:
Feign
。
Feign
是一个声明式的
Web Service
客户端,它的目的就是让
Web Service
调用更加简单。
Feign
提供了
HTTP
请求的模板,通过编写简单的接口和插入注解,就可以定义好
HTTP
请求的参数、格式、地址等信息。
而
Feign
则会完全代理
HTTP
请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。
Feign
整合了
Ribbon
和
Hystrix
(关于
Hystrix
我们后面再讲),可以让我们不再需要显式地使用这两个组件。
总起来说,
Feign
具有如下特性:
-
采用的是基于接口可插拔的注解支持,包括
Feign
注解和
JAX-RS
注解; -
支持可插拔的
HTTP
编码器和解码器; -
支持
Hystrix
和它的
Fallback
,具有熔断降级的能力; -
支持
Ribbon
的负载均衡,具有负载均衡的能力; -
支持
HTTP
请求和响应的压缩。
这看起来有点像我们
Spring MVC
模式的
Controller
层的
RequestMapping
映射。这种模式是我们非常喜欢的。
Feign
是用
@FeignClient
来映射服务的。
1.2 为什么使用
Feign
Feign
Feign
的首要目标就是减少
HTTP
调用的复杂性。在微服务调用的场景中,我们调用很多时候都是基于
HTTP
协议的服务,如果服务调用只使用提供
HTTP
调用服务的
HTTP Client
框架(e.g. Apache HttpComponnets、HttpURLConnection OkHttp 等),我们需要关注哪些问题呢?
相比这些
HTTP
请求框架,
Feign
封装了
HTTP
请求调用的流程,而且会强制使用者去养成面向接口编程的习惯(因为
Feign
本身就是要面向接口)。
1.3
Feign
详解
Feign
1.3.1 代码示例
首先第一步,在原来的基础上新建一个
Feign
模块,接着引入相关依赖,引入
Feign
依赖,会自动引入
Hystrix
依赖的,如下所示:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
application.yml
配置如下所示:
server:
port: 8083
spring:
application:
name: feign-consumer
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
接着在前面文章中的的的两个
provider1
和
provider2
两个模块的服务新增几个方法,如下代码所示:
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
System.out.println("访问来1了......");
return "hello1";
}
@RequestMapping("/hjcs")
public List<String> laowangs(String ids){
List<String> list = new ArrayList<>();
list.add("laowang1");
list.add("laowang2");
list.add("laowang3");
return list;
}
//新增的方法
@RequestMapping(value = "/hellol", method= RequestMethod.GET)
public String hello(@RequestParam String name) {
return "Hello " + name;
}
@RequestMapping(value = "/hello2", method= RequestMethod.GET)
public User hello(@RequestHeader String name, @RequestHeader Integer age) {
return new User(name, age);
}
@RequestMapping(value = "/hello3", method = RequestMethod.POST)
public String hello (@RequestBody User user) {
return "Hello "+ user. getName () + ", " + user. getAge ();
}
}
接着是上面代码所需用到的
User
类,代码如下所示:
public class User {
private String name;
private Integer age;
//序列化传输的时候必须要有空构造方法,不然会出错
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
//...getter setter省略
}
接下来用
Feign
的
@FeignClient(“服务名称”)
映射服务调用。代码如下所示:
package hjc;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.*;
//configuration = xxx.class 这个类配置Hystrix的一些精确属性
//value=“你用到的服务名称”
@FeignClient(value = "hello-service",fallback = FeignFallBack.class)
public interface FeignService {
//服务中方法的映射路径
@RequestMapping("/hello")
String hello();
@RequestMapping(value