网上很少有人把 Feign 单独作为一章来写,但我认为 Feign 也很重要,使用好 Feign 能更好的理解 RESTFUL 接口设计规范。如果想要用一篇文章来写好 Feign 我认为是很难的,我尽量用一篇文章来描述清楚。
Feign 是一个声明式 Web Service 客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud 对 Feign 进行了封装,使其支持了 Spring MVC 标准注解和 HttpMessageConverters。Feign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡。
在 Spring Cloud 中 Feign 是用作服务调用和客户端负载均衡的。Feign 可以配合 Spring Cloud 使用,也可以单独使用。
在不使用 Feign 之前,我们调用其它服务需要用到 httpclient 或者 okhttp 这样相对较重的框架,而且需要编写大量的代码。虽然 spring 中 RestTemplate 也可以灵活的使用,但是它不具备负载均衡的功能,需要我们自己实现;另外 RestTemplate 对配置化,支持的还不够友好,所以 Feign 应运而生。
我们先来看看 Feign 的单独使用。首先,需要导入 Maven 的相关配置:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.sourceEncoding>UTF-8</project.reporting.sourceEncoding> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-core</artifactId> <version>8.18.0</version> </dependency> <dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-gson</artifactId> <version>8.18.0</version> </dependency> </dependencies>
然后自定义一个远程调用接口,代码如下:
public interface GitHub { @RequestLine("GET /repos/{owner}/{repo}/contributors") List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); }
上面的 Contributor 类代码如下:
public class Contributor { String login; int contributions; }
然后对 Feign 的远程调用功能进行测试,代码如下:
public class FeignTest { public static void main(String... args) { //www.xttblog.com GitHub github = Feign.builder() .decoder(new GsonDecoder()) .target(GitHub.class, "https://api.github.com"); // Fetch and print a list of the contributors to this library. List<Contributor> contributors = github.contributors("OpenFeign", "feign"); for (Contributor contributor : contributors) { System.out.println(contributor.login + " (" + contributor.contributions + ")"); } } }
运行后,输出的结果我就不写了,大家可以自行的去测试。相关代码我已上传到 https://github.com/xmt1139057136/xttblog-cloud/xttblog-feign-github。
上面的案例,我们主要是对 Feign 有了一个简单的认识,在 Spring Cloud 中并不会这样的去使用。下面我们来看看在 Spring Cloud 中如何使用 Feign。
首先创建一个 xttblog-cloud-producer 项目。pom.xml 配置如下:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.13.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies>
application.yml 配置文件内容如下:
server: port: 8888 eureka: instance: hostname: localhost client: serviceUrl: defaultZone: http://${eureka.instance.hostname}:8761/eureka/ spring: application: name: xttblog-cloud-producer
然后编写一个服务提供者的 Controller,代码如下:
@RestController @RequestMapping("/cal") public class CalController { @RequestMapping("/add") public Integer add(@RequestParam Integer a, @RequestParam Integer b){ return a + b; } }
启动类的代码没有大的改动,具体如下:
@SpringBootApplication @EnableDiscoveryClient public class XttblogProducerApplication { public static void main(String[] args) { SpringApplication.run(XttblogProducerApplication.class, args); } }
至此,服务提供者我们已经写完了,下面我们来编写服务调用着代码。同样的先新建一个 xttblog-cloud-consumer 工程。pom.xml 代码如下:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.13.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Edgware.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <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> </dependencies>
接着是 application.yml 文件的代码:
server: port: 7777 eureka: instance: hostname: localhost client: serviceUrl: defaultZone: http://${eureka.instance.hostname}:8761/eureka/ spring: application: name: xttblog-cloud-consumer
再接着是消费者的 Controller 代码:
@RestController @RequestMapping("/test") public class ConsumerController { @Autowired private CalService calService; @Autowired private CalRemoteService calRemoteService; @RequestMapping("/add") public String add(@RequestParam Integer a, @RequestParam Integer b){ return a + "+" + b + "的RestTemplate调用结果为:" + calService.add(a, b); } @RequestMapping("/radd") public String rAdd(@RequestParam Integer a, @RequestParam Integer b){ return a + "+" + b + "的Cloud调用结果为:" + calRemoteService.add(a, b); } }
然后是 Feign 的远程调用的代码:
@FeignClient(name= "xttblog-cloud-producer") public interface CalRemoteService { @RequestMapping(value = "/cal/add") public String add(@RequestParam(value="a") Integer a, @RequestParam("b") Integer b); }
public interface CalService { public String add(Integer a, Integer b); }
@Service public class CalServiceImpl implements CalService{ @Autowired private RestTemplate restTemplate; @Bean //@LoadBalanced//启用ribbon负载均衡调用服务 public RestTemplate cteateRestTemplate(){ return new RestTemplate(); } @Override public String add(Integer a, Integer b) { String url = "http://localhost:8888/cal/add?a=" + a + "&b=" + b; ResponseEntity responseEntity = restTemplate.getForEntity(url,String.class); return responseEntity.getBody().toString(); } }
我这里有两个 Service 类,一个是使用 RestTemplate 调用服务,一个是 Feign 来调用;让大家比较一下两者的调用方式。
在使用 @FeignClient 注解后,必须在主启动类上加上 @EnableFeignClients 注解,否则调用不会成功。
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class XttblogConsumerApplication { public static void main(String[] args) { SpringApplication.run(XttblogConsumerApplication.class, args); } }
另外需要注意的是,在服务消费方必须引入 Feign 的依赖,否则启动时会报错。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
那有人会问了,为什么我引入注解时不报错,而是在运行时才报错呢?那是因为我们都是面向接口编程的。引入注解,并没有引入 Feign 的实现,所以会报错。
上面两个服务,我们都注册到了 Eureka,用的是 Spring Cloud 教程系列第二章的服务注册工程《Spring Cloud 教程第二章 服务的注册、发现、治理之 Eureka 实战》,具体可以到我的 github 上查看源码:https://github.com/xmt1139057136/xttblog-cloud/tree/master/xttblog-eureka-server。
写完上面的代码后,我们依次启动,xttblog-eureka-server、xttblog-cloud-producer、xttblog-cloud-consumer。然后浏览器地址栏里输入 http://localhost:7777/test/add?a=1&b=2 和 http://localhost:7777/test/radd?a=1&b=3 即可看到运行效果。
最后本文涉及的相关源码都已上传到:https://github.com/xmt1139057136/xttblog-cloud,喜欢的可以给个 star。
: » Spring Cloud 教程第五章 Feign 的声明式服务调用与负载均衡
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/251824.html