前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微服务声明式rest客户端之feign使用入门教程

微服务声明式rest客户端之feign使用入门教程

作者头像
lyb-geek
发布2022-03-10 13:51:14
1.8K0
发布2022-03-10 13:51:14
举报
文章被收录于专栏:Linyb极客之路Linyb极客之路

在本教程中,我们将介绍Feign。我们还将谈谈Spring Boot和Feign。 在本教程中,我们将了解如何使用Feign编写声明性REST客户端。它通过抽象出我们通常编写的样板代码,使编写Web客户端变得容易。我们需要做的就是声明一个接口并注释它及其方法。实际的实现将由框架在运行时完成,以及调用之间的各种消息转换。我们首先需要设置一个使用已知端点运行的示例REST API,以便我们可以使用feign客户端调用它们。

1.服务设置

我们的示例服务是一个简单的spring-boot应用程序,包含一个具有两个端点的REST控制器:

代码语言:javascript
复制
@RestController
public class ProductController {

 private static List < Product > productList = new ArrayList < > ();
 static {
  productList.add(new Product(1, "product-1", 12.0));
  productList.add(new Product(2, "product-2", 34.0));
  productList.add(new Product(3, "product-3", 9.0));
 }

 @GetMapping("/products")
 public ResponseEntity << ? > getProsucts() {

  return ResponseEntity.ok(productList);

 }

 @GetMapping("/product/{id}")
 public ResponseEntity << ? > getProsucts(@PathVariable int id) {

  Product product = findProduct(id);
  if (product == null) {
   return ResponseEntity.badRequest()
    .body("Invalid product Id");
  }

  return ResponseEntity.ok(product);

 }

 private Product findProduct(int id) {
  return productList.stream()
   .filter(user -> user.getId()
    .equals(id))
   .findFirst()
   .orElse(null);
 }

}

两个端点是' /products'和' product/{id}',它们返回一个产品列表和一个基于分别传递的id的产品。如果未找到产品,则返回HTTP.BAD_REQUEST响应。以下是application.properties:

代码语言:javascript
复制
server.port=8081
spring.application.name=product-service

Product服务将在端口8081上运行

2.客户端安装

创建Spring启动应用程序的最佳方法是Spring Initializr。选择Spring Boot版本,并添加“Web”,“Feign”依赖项。将它生成为Maven项目,你就完成了。请注意pom.xml中的以下依赖项:

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Feign最初由Netflix赞助,但后来开源。在spring-boot 1.x版本中,feign依赖项来自Netflix但是从spring-boot 2.x开始使用openfeign。通过在主类中添加' @EnableFeignClients' 使项目能够使用Feign客户端:

代码语言:javascript
复制
@SpringBootApplication

@EnableFeignClients

public
 
class
 
FeignClientExampleApplication
 {



 
public
 
static
 
void
 main(
String
[] args) {

  
SpringApplication
.run(
FeignClientExampleApplication
.
class
, args);

 }

}

让我们来定义我们的产品服务Feign客户端。首先,我们必须创建一个接口

ProductServiceClient,并通过@FeignClient指定名称和产品服务的URL运行来对其进行注释。至于方法,我们只需要声明它并注释就像Spring MVC样式一样。我们还需要告诉它可能需要哪些输入以及转换所需的响应类型。

代码语言:javascript
复制
@FeignClient
(name = 
"product-service"
, url = 
"http://localhost:8081"
)

public
 interface 
ProductServiceClient
 {



 
@RequestMapping
(value = 
"/products"
, method = 
RequestMethod
.GET)

 
public
 
List
 < 
Product
 > getAllProducts();



 
@RequestMapping
(value = 
"/product/{id}"
, method = 
RequestMethod
.GET)

 
public
 
Product
 getProduct(
@PathVariable
(
"id"
) 
int
 productId);



}

Spring将使用openfeign在运行时实现此接口的实现。我们必须在项目中定义Product类,因为我们正在将响应转换为它:

代码语言:javascript
复制
public
 
class
 
Product
 {



 
private
 
Integer
 id;



 
private
 
String
 name;



 
private
 
double
 price;



 
public
 
Product
(
Integer
 id, 
String
 name, 
double
 price) {

  
this
.id = id;

  
this
.name = name;

  
this
.price = price;

 }



 
public
 
Integer
 getId() {

  
return
 id;

 }



 
public
 
String
 getName() {

  
return
 name;

 }



 
public
 
double
 getPrice() {

  
return
 price;

 }

}

现在让我们在AppController中使用这个ProductServiceClient。为此,我们需要@Autowired将ProductServiceClient放入我们的控制器中。

代码语言:javascript
复制
@RestController

public
 
class
 
AppController
 {



 
@Autowired

 
ProductServiceClient
 productServiceClient;



 
@GetMapping
(
"/fetchProducts"
)

 
public
 
ResponseEntity
 << ? > fetchProducts() {



  
return
 
ResponseEntity
.ok(productServiceClient.getAllProducts());

 }



 
@GetMapping
(
"/fetchProduct/{id}"
)

 
public
 
ResponseEntity
 << ? > fetchProduct(
@PathVariable
 
int
 id) {



  
return
 
ResponseEntity
.ok(productServiceClient.getProduct(id));

 }



}

这就是我们所要做的。让我们使用Postman进行测试: http://localhost:8080/fetchProduct/1 在简单代码的背后,所有样板代码都由spring和openfeign库处理。这样可以减少代码,减少出错的机会。 3.处理错误的错误 默认情况下,Feign仅针对任何错误情况(其中响应不是2XX或者存在转换错误等)抛出FeignException。 但是,如果找不到产品ID,您可能希望捕获这些错误并在最终处理响应,就像产品服务引发的BAD_REQUEST错误一样。我们首先定义我们的自定义ProductNotFound异常:

代码语言:javascript
复制
public class ProductNotFoundException extends RuntimeException {

 private static final long serialVersionUID = 1 L;

 public ProductNotFoundException(String msg) {
  super(msg);
 }
}

现在让我们为这个应用定义我们的异常处理程序:

代码语言:javascript
复制
@RestControllerAdvice
public class AppExceptionHandler {

 @ResponseBody
 @ExceptionHandler(value = ProductNotFoundException.class)
 public ResponseEntity << ? > handleException(ProductNotFoundException exception) {
  return ResponseEntity.status(HttpStatus.NOT_FOUND)
   .body(exception.getMessage());
 }

}

现在要捕获FeignException并提供您自己的实现,您需要实现feign.codec.ErrorDecoder并将其在Spring应用程序上下文中注册为bean 。

代码语言:javascript
复制
@Component
public class AppFeignErrorDecoder implements ErrorDecoder {

 private final ErrorDecoder defaultErrorDecoder = new Default();

 @Override
 public Exception decode(String methodKey, Response response) {
  if (response.status() >= 400 && response.status() <= 499) {
   throw new ProductNotFoundException("Product Not Found");
  }

  return defaultErrorDecoder.decode(methodKey, response);
 }

}

如您所见,我们捕获了所有4xx错误并抛出了我们自己的自定义异常。

4. .使用Feign和Eureka和Ribbon 通常在微服务架构中,所有服务都注册到像Eureka这样的注册服务,并且可能存在运行相同服务的多个实例。因此,您可能不希望在Feign客户端中对URL进行硬编码,也希望连接到响应更快的服务实例。 我们来设置一个Eureka服务器。同样,我们将使用Spring Initializr来创建它。 然后您需要做的就是添加@EnableEurekaServer到主类:

代码语言:javascript
复制
@SpringBootApplication

@EnableEurekaServer

public
 
class
 
EurekaServerApplication
 
{



 
public
 
static
 
void
 main
(
String
[]
 args
)
 
{

  
SpringApplication
.
run
(
EurekaServerApplication
.
class
,
 args
);

 
}

}

以下是application.properties:server.port=8761。因此,我们的Eureka服务器将在8761上运行,这是Spring的推荐端口。 现在注册我们的2项服务。您只需在我们项目中添加以下依赖项pom.xml:

代码语言:javascript
复制
<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

</dependency>

添加@EnableDiscoveryClient到应用程序的主类,如:

代码语言:javascript
复制
@SpringBootApplication

@EnableDiscoveryClient

@EnableFeignClients

public
 
class
 
FeignClientExampleApplication
 {



 
public
 
static
 
void
 main(
String
[] args) {

  
SpringApplication
.run(
FeignClientExampleApplication
.
class
, args);

 }

}

(注:Springboot2 已经不需要@EnableDiscoveryClient) 启动这两个应用程序,您将看到他们在Eureka服务器中注册了。 现在让我们从ProductServiceClient中删除硬编码的URL:

代码语言:javascript
复制
@FeignClient
(
name 
=
 
"product-service"
 
/*, url = "http://localhost:8081"*/
 
)

public
 interface 
ProductServiceClient
 
{

 
// same as previous

}

现在,幕后,ProductServiceClient将使用name属性从Eureka服务器获取URL (“product-service”)。Ribbon是一个客户端负载均衡器,它附带了我们所包含的依赖项。这将自动获取最佳服务器以供我们进行其余调用。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.服务设置
  • 2.客户端安装
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档