前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud学习笔记(3):使用Feign实现声明式服务调用

SpringCloud学习笔记(3):使用Feign实现声明式服务调用

作者头像
布禾
修改2020-11-19 10:09:34
3630
修改2020-11-19 10:09:34
举报
文章被收录于专栏:好好学习,天天向上

简介

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:
代码语言:javascript
复制
<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:
代码语言:javascript
复制
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
代码语言:javascript
复制
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:
代码语言:javascript
复制
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:
代码语言:javascript
复制
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构造带参数的请求,首先对提供者和消费者做如下更改:

代码语言:javascript
复制
//提供者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注解:

代码语言:javascript
复制
@FeignClient("sc-provider")
public interface BookService {
	@GetMapping("/book/list")	
	public String getBookList(@RequestParam("param1") String param1, @RequestParam("param2") Integer param2);
}
解决方法2

将参数封装到Map里,更改消费者Feign接口和Controller:

代码语言:javascript
复制
@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(可以建一个公共模块,然后在提供者和消费者中添加依赖):
代码语言:javascript
复制
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.更改提供者和消费者相关类
代码语言:javascript
复制
//提供者
@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,提供者控制台输出:
代码语言:javascript
复制
Params [param1=Java, param2=520]
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-09-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 项目介绍
  • 基于Feign声明式调用的消费者
    • 1.在父模块下创建子模块项目sc-consumer-feign,pom.xml:
      • 2.创建启动类feign.FeignApplication:
        • 3.创建Feign声明式接口:feign.inter.BookService
          • 4.创建调用提供者服务的Controller:
            • 5.创建application.yml:
              • 6.依次启动注册中心sc-eureka、提供者sc-provider、消费者sc-consumer-feign,并访问http://localhost:8084/feign/getBookList:
              • 带参数的请求
                • 解决方法1
                  • 解决方法2
                  • 自定义类型的参数
                    • 1.分别在提供者和消费者中创建类Params(可以建一个公共模块,然后在提供者和消费者中添加依赖):
                      • 2.更改提供者和消费者相关类
                        • 3.依次启动注册中心sc-eureka、提供者sc-provider、消费者sc-consumer-feign,并访问http://localhost:8084/feign/getBookList,提供者控制台输出:
                        相关产品与服务
                        负载均衡
                        负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档