简介
Feign 是一个声明式的 web Service 客户端, 它简化了 Web 服务客户端的编写操作, 相对于 Ribbon+RestTemplate 的方式, 开发者只需通过简单的接口和注解来调用 HTTP API. 它支持 Spring MVC 注解和 JAX-RS 注解, 还支持可插拔式的编码器和解码器. 整合了 Eureka,Ribbon 和 Hystrix, 具有可插拔, 基于注解, 负载均衡, 服务熔断等一系列便捷功能.
项目介绍
sc-parent, 父模块(请参照 SpringCloud 学习笔记(1):Eureka 注册中心)
sc-eureka, 注册中心(请参照 SpringCloud 学习笔记(1):Eureka 注册中心)
sc-provider, 提供者(请参照 SpringCloud 学习笔记(1):Eureka 注册中心)
sc-consumer-feign, 基于 Feign 声明式调用的消费者
基于 Feign 声明式调用的消费者
1. 在父模块下创建子模块项目 sc-consumer-feign,pom.xml:
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.cf</groupId>
- <artifactId>sc-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <artifactId>sc-consumer-feign</artifactId>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- </dependencies>
- </project>
2. 创建启动类 feign.FeignApplication:
- package feign;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.openfeign.EnableFeignClients;
- @SpringBootApplication
- @EnableFeignClients
- public class FeignApplication {
- public static void main(String[] args) {
- SpringApplication.run(FeignApplication.class, args);
- }
- }
3. 创建 Feign 声明式接口: feign.inter.BookService
- package feign.inter;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.Web.bind.annotation.GetMapping;
- @FeignClient("sc-provider")
- public interface BookService {
- @GetMapping("/book/list")
- public String getBookList();
- }
4. 创建调用提供者服务的 Controller:
- package provider.controller;
- import org.springframework.Web.bind.annotation.GetMapping;
- import org.springframework.Web.bind.annotation.RequestMapping;
- import org.springframework.Web.bind.annotation.RestController;
- @RequestMapping("/book")
- @RestController
- public class BookController {
- @GetMapping("/list")
- public String getBookList(){
- return "[\"Java 入门到放弃 \",\"C++ 入门到放弃 \",\"Python 入门到放弃 \",\"C 入门到放弃 \"]";
- }
- }
5. 创建 application.YAML:
- server:
- port: 8084
- spring:
- application:
- name: sc-consumer-feign
- eureka:
- client:
- registerWithEureka: false
- serviceUrl:
- defaultZone: http://localhost:8080/eureka/
6. 依次启动注册中心 sc-eureka, 提供者 sc-provider, 消费者 sc-consumer-feign, 并访问 http://localhost:8084/feign/getBookList:
Feign 基于 Ribbon 实现, 也具有 Ribbon 负载均衡的特性, 可以将调用的提供者服务换成 sc-provider-random(请参照 SpringCloud 学习笔记 (2): 使用 Ribbon 负载均衡) 来测试.
带参数的请求
上面例子没有涉及到参数的传递, 接下来测试下如何使用 Feign 构造带参数的请求, 首先对提供者和消费者做如下更改:
- // 提供者 Controller 添加了两个参数, 并打印到控制台.
- @RequestMapping("/book")
- @RestController
- public class BookController {
- @GetMapping("/list")
- public String getBookList(String param1, Integer param2){
- System.out.println(param1 + ":" + param2);
- return "[\"Java 入门到放弃 \",\"C++ 入门到放弃 \",\"Python 入门到放弃 \",\"C 入门到放弃 \"]";
- }
- }
- // 消费者 Feign 接口和 Controller 添加参数
- @FeignClient("sc-provider")
- public interface BookService {
- @GetMapping("/book/list")
- public String getBookList(String param1, Integer param2);
- }
- @RequestMapping("/feign")
- @RestController
- public class FeignController {
- @Autowired
- private BookService bookService;
- @GetMapping("/getBookList")
- public String getBookList(){
- return bookService.getBookList("Java", 520);
- }
- }
依次启动注册中心 sc-eureka, 提供者 sc-provider, 消费者 sc-consumer-feign, 启动消费者 sc-consumer-feign 时会启动失败:
java.lang.IllegalStateException: Method has too many Body parameters: public abstract java.lang.String feign.inter.BookService.getBookList(java.lang.String,java.lang.Integer)
解决方法 1
更改 Feign 接口, 为参数添加 @RequestParam 注解:
- @FeignClient("sc-provider")
- public interface BookService {
- @GetMapping("/book/list")
- public String getBookList(@RequestParam("param1") String param1, @RequestParam("param2") Integer param2);
- }
解决方法 2
将参数封装到 Map 里, 更改消费者 Feign 接口和 Controller:
- @FeignClient("sc-provider")
- public interface BookService {
- @GetMapping("/book/list")
- public String getBookList(@RequestParam Map<String, Object> paramMap);
- }
- @RequestMapping("/feign")
- @RestController
- public class FeignController {
- @Autowired
- private BookService bookService;
- @GetMapping("/getBookList")
- public String getBookList(){
- Map<String,Object> paramMap = new HashMap<String, Object>();
- paramMap.put("param1", "Java");
- paramMap.put("param2", 520);
- return bookService.getBookList(paramMap);
- }
- }
在参数较多的情况下, 该方式可以简化 Feign 接口的编写.
自定义类型的参数
OpenFeign 的 @QueryMap 注解支持将自定义类型用于 GET 参数映射, 由于 @QueryMap 和 Spring 不兼容, Spring Cloud OpenFeign 提供了一个等价的 @SpringQueryMap 注解, 可以用于自定义类型和 Map 类型的参数映射. 下面将使用自定义类型 Params 作为参数, 使用 @SpringQueryMap 注解来处理自定义类型的参数映射.
1. 分别在提供者和消费者中创建类 Params(可以建一个公共模块, 然后在提供者和消费者中添加依赖):
- public class Params {
- private String param1;
- private Integer param2;
- public String getParam1() {
- return param1;
- }
- public void setParam1(String param1) {
- this.param1 = param1;
- }
- public Integer getParam2() {
- return param2;
- }
- public void setParam2(Integer param2) {
- this.param2 = param2;
- }
- @Override
- public String toString() {
- return "Params [param1=" + param1 + ", param2=" + param2 + "]";
- }
- public Params(String param1, Integer param2) {
- this.param1 = param1;
- this.param2 = param2;
- }
- public Params() {}
- }
2. 更改提供者和消费者相关类
- // 提供者
- @RequestMapping("/book")
- @RestController
- public class BookController {
- @GetMapping("/list")
- public String getBookList(Params params){
- System.out.println(params.toString());
- return "[\"Java 入门到放弃 \",\"C++ 入门到放弃 \",\"Python 入门到放弃 \",\"C 入门到放弃 \"]";
- }
- }
- // 消费者
- @FeignClient("sc-provider")
- public interface BookService {
- @GetMapping("/book/list")
- public String getBookList(@SpringQueryMap Params params);
- }
- @RequestMapping("/feign")
- @RestController
- public class FeignController {
- @Autowired
- private BookService bookService;
- @GetMapping("/getBookList")
- public String getBookList(){
- Params params = new Params("Java", 520);
- return bookService.getBookList(params);
- }
- }
3. 依次启动注册中心 sc-eureka, 提供者 sc-provider, 消费者 sc-consumer-feign, 并访问 http://localhost:8084/feign/getBookList, 提供者控制台输出:
Params [param1=Java, param2=520]
来源: https://www.cnblogs.com/seve/p/11512249.html