上一篇分享了使用 Ribbon 进行服务的消费(调用),这一篇中我们分享一下使用 feign 的服务消费。
一、什么是 feign
首先,当然是要说说什么是 feign,为什么要用 feign 呢?
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same
HttpMessageConverters
used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.
以上这段话来自 Spring Cloud 官网,http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_spring_cloud_openfeign
这段话里已经说明了 feign 是一个声明式的 web 服务客户端,它简化了我们编写 web 服务客户端的操作。并且它使用注解,具有可插拔、负载均衡、服务熔断等一系列便捷功能。
有人可能会问了,前一篇中我们使用 Ribbon 不也是能够进行服务的调用,并且也具备负载均衡功能嘛,为什么还要用 feign,是多此一举吗?答案当然是不,要不然谁会没事儿多搞个 feign 来浪费大家时间呢?
Ribbon 与 Feign 的关系?
简单地理解为 Ribbon 是个更通用的 http 客户端工具,而 Feign 则是基于 Ribbon 开发出的更自定义化以供 Spring Cloud 便捷使用的 http 客户端工具。
而且 Feign 的使用比 Ribbon 更简单,只需要通过注解便可简单实现服务的消费。
总结
1 Feign 是一个 Http 客户端
2 支持 Feign 注解和 JAX-RS 注解
3 Feign 基于 Ribbon 实现,具有 Ribbon 的功能,包括负载均衡
4 Feign 具备 Hystrix 的服务熔断功能(服务熔断:防止由于服务调用时的网络问题或服务掉线而引发的一系列问题)
二、Feign 使用示例
2.1 创建项目
这里使用之前创建的 logistics-service 项目作为示例
2.2 添加依赖
在 pom.xml 中添加 feign 的依赖,并使用 maven 导入依赖。
org.springframework.cloud
spring-cloud-starter-openfeign
2.3 添加 Feign 注解
在项目的启动类上添加 @EnableFeignClients 的注解
package com.jiangzhuolin.logisticsservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
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;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LogisticsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(LogisticsServiceApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
2.4 定义 Feign 接口
在 logistics-service 项目中定义一个接口来进行 feign 的服务消费定制。
package com.jiangzhuolin.logisticsservice.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(value = "user-service")
public interface ILogisticsService {
@RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
String getUserInfo(@PathVariable(value = "id") long id);
}
- @FeignClient() 声明了这是一个 Feign 客户端,里面的 value = "user-service" 表示要调用的是 user-service 这个服务(在 application.yml 配置的 application.name)。
- @RequestMapping 注意区分此处的 RequestMapping 用于指定要调用的对方服务的 URI,而不是对外提供的 URI。上面的代码表示要调用的是 user-service 服务的 /user/{id} 这个接口,其中 id 为 路径参数。
- getUserInfo() 方法里的参数表示传递给调用服务的接口(user service 服务)的参数,如此处表示调用 getUserInfo 方法传递的 id 将作为 user-service 服务的 /user/{id} 接口的一个路径参数被传递
2.5 修改 logistics 服务的 controller
将 LogisticsController 中的接口调用由原来的 Restemplate + Ribbon 改为 Feign。
package com.jiangzhuolin.logisticsservice.controller;
import com.jiangzhuolin.logisticsservice.service.ILogisticsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/logistics/")
public class LogisticsController {
@Autowired
private ILogisticsService logisticsService;
@RequestMapping(value = "/message")
public String message(long userId) {
String response = logisticsService.getUserInfo(userId);
return response;
}
}
- @Autowired 注入 ILogisticsService
- 在 Controller 方法中直接调用 ILogisticsService 中定义的 Feign 的调用方法。
2.6 启动项目并验证
直接在本地启动 logistics-service 项目,并验证接口调用。
调用 logistics-service 的接口,可以看到通过 logistics-service 服务的接口,我们拿到了 user-service 服务的数据,而这个过程中,我们只是加了几个注解,配置了几个参数即可。
总结
从上面的示例我们可以明显地看出,Feign 的作用就是为了极大的简化我们在微服务架构下的不同服务间调用。并且贴心地为我们解决了负载均衡与服务熔断的两个难点。
Feign 的使用还有更多的自定义,官方地址如下:
http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_spring_cloud_openfeign
本文的 github 源码地址如下:
https://github.com/jiangzhuolin/logistics-service