zoukankan      html  css  js  c++  java
  • SpringCloud学习笔记(3):使用Feign实现声明式服务调用

    简介

    Feign是一个声明式的Web Service客户端,它简化了Web服务客户端的编写操作,相对于Ribbon+RestTemplate的方式,开发者只需通过简单的接口和注解来调用HTTP API。它支持Spring MVC注解和JAX-RS注解,还支持可插拔式的编码器和解码器。整合了Eureka,Ribbon和Hystrix,具有可插拔、基于注解、负载均衡、服务熔断等一系列便捷功能。

    项目介绍

    1. sc-parent,父模块(请参照SpringCloud学习笔记(1):Eureka注册中心)
    2. sc-eureka,注册中心(请参照SpringCloud学习笔记(1):Eureka注册中心)
    3. sc-provider,提供者(请参照SpringCloud学习笔记(1):Eureka注册中心)
    4. 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 feign.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import feign.inter.BookService;
    
    @RequestMapping("/feign")
    @RestController
    public class FeignController {
    	@Autowired
    	private BookService bookService;
    	
    	@GetMapping("/getBookList")
    	public String getBookList(){
    		return bookService.getBookList();
    	}
    }
    

    5.创建application.yml:

    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]
    
  • 相关阅读:
    分库分表(1) --- 理论
    Elasticsearch(10) --- 内置分词器、中文分词器
    Elasticsearch(9) --- 聚合查询(Bucket聚合)
    Elasticsearch(8) --- 聚合查询(Metric聚合)
    Elasticsearch(7) --- 复合查询
    Elasticsearch(6) --- Query查询和Filter查询
    Elasticsearch(5) --- 基本命令(集群相关命令、索引CRUD命令、文档CRUD命令)
    第二周 Word版面设计
    第六周 Word目录和索引
    第五周 Word注释与交叉引用
  • 原文地址:https://www.cnblogs.com/seve/p/11512249.html
Copyright © 2011-2022 走看看