1.Feign是什么?
官网地址:https://cloud.spring.io/spring-cloud-openfeign/single/spring-cloud-openfeign.html#spring-cloud-feign
官网的解释是:
Feign是一个声明性的Web服务客户端。它使编写Web服务客户端变得更容易。要使用Feign,请创建一个界面并对其进行注释。它具有可插入的注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持,并使用了HttpMessageConverters
Spring Web中默认使用的注释。Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载均衡的http客户端。
2.为什么要使用Feign?
我们知道,方法里面调用远程服务,使用HttpClient就可以,而且HttpClient比Feign更早出现,那我为什么还要再去使用Feign呢?首先,HttpClient前几年确实特别流行,也特别好用,但是,这个项目现在已经停止维护了,所以社区不会在那么活跃,采坑了不一定有人为你解答问题。其次,我们在使用HttpClient时,基本还需要再次封装一下get和post方法,但是,我又比较懒,我不想写那么方法。这时候,我就想到Feign。Feign 支持自定义编码器与解码器,支持失败重试与服务熔断。总之,Httpclient支持的,它基本都支持,而且实现方式更优雅。
3.如何基于Feign实现HttpClient的功能
3.1 添加Feign的相关依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.1.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>9.3.1</version>
<scope>compile</scope>
</dependency>
3.2 配置将调用服务域名
## 在yml配置文件配置服务域名,因为不同环境服务域名可能不一样
## feign远程调用地址
spring:
feign:
firstUrl: http://localhost:8088
3.3 添加服务方法
**
* @author yigen shi
* @version 1.0
* @date 2019/7/23 17:26
* @description
*/
@Headers({"Accept: application/json"})
public interface FirstConnector {
@RequestLine("GET /api/v1/get?value={value}")
BaseResponse<String> firstGetRequest(@Param("value") String value);
@RequestLine("GET /api/v1/get/{value}")
BaseResponse<String> anotherGetRequest(@Param("value") String value);
@RequestLine("POST /api/v1/post")
@Body("request")
BaseResponse<String> firstPostRequest(FirstFeignRequest request);
}
3.4 封装Client对象以及初始化
/**
* @author yigen shi
* @version 1.0
* @date 2019/7/23 17:23
* @description
*/
@Component
public class FirstClient {
@Value("${spring.feign.firstUrl}")
private String firstUrl;
@Autowired
private FirstConnector getConnector() {
return Feign.builder()
// 用于解析json
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
// 设置超时时间
.options(new Request.Options(5000, 8000))
// 熔断 重试次数
.retryer(new Retryer.Default(5000, 5000, 3))
.target(FirstConnector.class, firstUrl);
}
public BaseResponse<String> firstGetRequest(String value) {
return this.getConnector().firstGetRequest(value);
}
public BaseResponse<String> anotherGetRequest(String value) {
return this.getConnector().anotherGetRequest(value);
}
public BaseResponse<String> firstPostRequest(FirstFeignRequest request) {
return this.getConnector().firstPostRequest(request);
}
}
3.5 方法里面调用client里面的方法
/**
* @author yigen shi
* @version 1.0
* @date 2019/7/23 17:38
* @description
*/
@Api
@RestController
@RequestMapping("/api/v1/")
public class FeignController {
private final FirstClient firstClient;
@Autowired
public FeignController(FirstClient firstClient) {
this.firstClient = firstClient;
}
@ApiOperation("第一个feign的get方法")
@GetMapping("/get")
public BaseResponse<String> firstGet(@RequestParam("value") String value) {
return firstClient.firstGetRequest(value);
}
@ApiOperation("另一个feign的get方法")
@GetMapping("/get/{value}")
public BaseResponse<String> anotherGet(@PathVariable("value") String value) {
return firstClient.anotherGetRequest(value);
}
@ApiOperation("第一个feign的post方法")
@PostMapping("/post")
public BaseResponse<String> firstPost(@RequestBody FirstFeignRequest request){
return firstClient.firstPostRequest(request);
}
}
这里只是对client的方法的返回值直接进行了返回,更多情况的是,通过client调用远程服务获取结果之后,在进行封装,之后返回结果。
3.6 服务方方法示例(因为只是为了做示例,所以写很简单)
@ApiOperation("对外提供get测试接口")
@GetMapping("/get")
public BaseResponse<String> firstGet(String value) {
String data = "hello " + value;
return new BaseResponse<>(data);
}
@ApiOperation("对外提供get测试接口")
@GetMapping("/get/{value}")
public BaseResponse<String> anotherGet(@PathVariable("value") String value) {
String data = "hello " + value;
return new BaseResponse<>(data);
}
@ApiOperation("对外提供post测试接口")
@PostMapping("/post")
public BaseResponse<String> firstPost(@RequestBody FirstFeignRequest request) {
String data = "hello " + request.getName() + ", your id is " + request.getId();
return new BaseResponse<>(data);
}
现在,你已经实现在方法里面调用远程服务就如同调用本地方法,而且可以根据不同环境切换服务方域名,还支持服务熔断与失败重试功能,是不是觉得HttpClient优雅很多?