深入浅出 -- 系统架构之微服务中OpenFeign最佳实践

2024-04-06 01:12

本文主要是介绍深入浅出 -- 系统架构之微服务中OpenFeign最佳实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前面我们讲了一下 Ribbon 和 RestTemplate 实现服务端通信的方法,Ribbon 提供了客户端负载均衡,而 RestTemplate 则对 http 进行封装,简化了发送请求的流程,两者互相配合,构建了服务间的高可用通信。

但在使用后也会发现,RestTemplate 只是对 HTTP 做了简单的封装,像发送请求的 URL、参数、请求头、请求体这些细节都需要我们自己处理,如此底层的操作都暴露出来肯定是不利于团队间协作的,因此就需要一种封装度更高,使用更简单的技术来屏蔽通信底层的复杂度,这里就来到了我们这篇文章介绍的重点了:OpenFeign 技术

为了便于理解,我们这里通过一个具体的案例来配合理解。

一、案例背景

在某电商平台的订单业务中,为了保证商品不超卖,我们需要在下单时查询商品库存,如有库存则创建订单,继续支付流程,如果库存为 0,则提示用户库存不足,无法下单。这里我们来定义订单服务(order-service)和仓储服务(warehouse-service)。总体流程如下:

在上述业务中,订单服务是依赖仓储服务的,那仓储服务就是服务提供者订单服务就是服务消费者,梳理清思路后,我们来使用代码还原这个场景。

二、创建服务提供者(warehouse-service)

仓储服务做为服务提供者,就是标准的 springboot 工程,我们先创建一个 springboot 工程。

1、工程创建

利用 Spring Initializr 向导创建 warehouse-service 工程(前面文章有创建步骤,不明白的可以去看一下)。确保在创建后的 pom.xml 中有如下引用:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>

2、配置注册中心

在创建好的工程中的 application.yml 文件中新增 Nacos 通信配置。

spring:application:name: warehouse-service #应用/微服务名字cloud:nacos:discovery:server-addr: 106.14.221.171:8848 #nacos服务器地址username: nacos #用户名密码password: nacosserver:port: 80

3、创建库存实体类

创建库存实体类,保存库存信息。

package com.example.warehouseservice.dto;//库存商品对象public class Stock {private Long skuId; //商品品类编号private String title; //商品与品类名称private Integer quantity; //库存数量private String unit; //单位private String description; //描述信息//带参构造函数public Stock(Long skuId, String title, Integer quantity, String unit) {this.skuId = skuId;this.title = title;this.quantity = quantity;this.unit = unit;}//getter and setter省略...}

4、创建控制器(controller)

创建仓储服务控制器 WarehouseController,通过一个 getStock()方法传入商品编号,返回具体的库存数据。我们这里采用数据模拟的方式,定义两个商品库存:编号为1101 的是紫色 256G iPhone15,库存 32 台,编号1102 的是白色 256G iPhone15,库存为 0

package com.example.warehouseservice.controller;//省略 import 部分//仓储服务控制器@RestControllerpublic class WarehouseController {/*** 查询对应 skuId 的库存状况* @param skuId skuId* @return Stock 库存对象*/@GetMapping("/stock")public Stock getStock(Long skuId){Map result = new HashMap();Stock stock = null;if(skuId == 1101l){//模拟有库存商品stock = new Stock(1101l, "Apple iPhone 15 128GB 紫色", 32, "台");stock.setDescription("Apple 11 紫色版对应商品描述");}else if(skuId == 1102l){//模拟无库存商品stock = new Stock(1101l, "Apple iPhone 15 256GB 白色", 0, "台");stock.setDescription("Apple 11 白色版对应商品描述");}else{//演示案例,暂不考虑无对应 skuId 的情况}return stock;}}

5、服务启动

上述代码完成后,我们打包部署到服务器上,启动成功后,可以在 Nacos 注册中心中看到注册状态

再在浏览器中访问 url 来查看服务返回的数据:

http://192.168.3.2/stock?skuId=1101{skuId: 1101,title: "Apple iPhone 15 128GB 紫色",quantity : 32,unit: "台",description:"Apple 11 紫色版对应商品描述"}

至此,我们服务提供者 warehouse-service 就开发完成了,下面我们来开发服务消费者。

三、创建服务消费者(order-service)

1、工程创建

我们还是使用 Spring initializr 创建一个 order-service 工程,并确保 pom.xml 中引入如下包:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><version>2.2.5.RELEASE</version></dependency>

2、启用 OpenFeign

创建完并添加好工程依赖包后,我们需要在应用入口 OrderServiceApplication 中添加@EnableFeignClients 注解,这里是为了通知 Spring 启用 OpenFeign 声明式通信。

package com.example.orderservice;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication@EnableFeignClients //启用OpenFeignpublic class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}}

3、配置 Nacos

默认的 OpenFeign 并不需要任何的配置,我们在 application.yml 配置一下 Nacos。

spring:application:name: order-servicecloud:nacos:discovery:server-addr: 106.14.221.171:8848username: nacospassword: nacosserver:port: 80

4、创建 OpenFeign 通信接口和响应对象

package com.example.orderservice.feignclient;import com.example.orderservice.dto.Stock;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;@FeignClient("warehouse-service")public interface WarehouseServiceFeignClient {@GetMapping("/stock")public Stock getStock(@RequestParam("skuId") Long skuId);}

在 order-service 工程下,创建一个 feignclient 包用于保存通信接口。OpenFeign 通过“接口+注解”形式描述数据传输逻辑,并不需要我们编写具体实现代码便能实现服务间高可用通信。

@FeignClient 注解说明当前接口为 OpenFeign 通信客户端,参数值 warehouse-service 为服务提供者 ID,这一项必须与 Nacos 注册 ID 保持一致。在 OpenFeign 发送请求前会自动在 Nacos 查询 warehouse-service 所有可用实例信息,再通过内置的 Ribbon 负载均衡选择一个实例发起 RESTful 请求,进而保证通信高可用.

package com.lagou.orderservice.dto;//消费者端接收响应Stock对象public class Stock {private Long skuId; //商品品类编号private String title; //商品与品类名称private Integer quantity; //库存数量private String unit; //单位@Overridepublic String toString() {return "Stock{" +"skuId=" + skuId +", title='" + title + ''' +", quantity=" + quantity +", unit='" + unit + ''' +'}';}//getter与setter省略}

声明的方法结构,接口中定义的方法通常与服务提供者的方法定义保持一致。这里有个非常重要的细节:用于接收数据的 Stock 对象并不强制要求与提供者端 Stock 对象完全相同,消费者端的 Stock 类可以根据业务需要删减属性,但属性必须要与提供者响应的 JSON 属性保持一致。距离说明,我们在代码发现消费者端 Stock 的包名与代码与提供者都不尽相同,而且因为消费者不需要 description 属性便将其删除,其余属性只要保证与服务提供者响应 JSON 保持一致,在 OpenFeign 获取响应后便根据 JSON 属性名自动反序列化到 Stock 对象中。

5、接口注入,远程调用

在消费者 Controller 中对 FeignClient 接口进行注入,像调用本地方法一样调用即可。

package com.example.orderservice.controller;import com.example.orderservice.dto.Stock;import com.example.orderservice.feignclient.WarehouseServiceFeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;import java.util.LinkedHashMap;import java.util.Map;@RestControllerpublic class OrderController {//利用@Resource将IOC容器中自动实例化的实现类对象进行注入@Resourceprivate WarehouseServiceFeignClient warehouseServiceFeignClient;/*** 创建订单业务逻辑* @param skuId 商品类别编号* @param salesQuantity 销售数量* @return*/@GetMapping("/create_order")public Map createOrder(Long skuId , Long salesQuantity){Map result = new LinkedHashMap();//查询商品库存,像调用本地方法一样完成业务逻辑。Stock stock = warehouseServiceFeignClient.getStock(skuId);System.out.println(stock);if(salesQuantity <= stock.getQuantity()){//创建订单相关代码,此处省略//CODE=SUCCESS代表订单创建成功result.put("code" , "SUCCESS");result.put("skuId", skuId);result.put("message", "订单创建成功");}else{//code=NOT_ENOUGN_STOCK代表库存不足result.put("code", "NOT_ENOUGH_STOCK");result.put("skuId", skuId);result.put("message", "商品库存数量不足");}return result;}}

6、部署测试

将消费者部署后,我们尝试调用消费者的创建订单接口,如传入 1101 编号,则会出现以下返回:

http://192.168.3.3/create_order?skuId=1101&salesQuantity=1{code: "SUCCESS",skuId: 1101,message: "订单创建成功"}

如传入 1102 编号,则会出现以下返回:

http://192.168.3.3/create_order?skuId=1102&salesQuantity=1{code: "NOT_ENOUGH_STOCK",skuId: 1102,message: "商品库存数量不足"}

这里已经基于 OpenFeign 实现了服务间通信。

到这里,我们 SpringCloud 集成 OpenFeign 的工作就完成了,大家可以按照自己的业务愉快的撸码了。

这篇关于深入浅出 -- 系统架构之微服务中OpenFeign最佳实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/878641

相关文章

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

TP-Link PDDNS服将于务6月30日正式停运:用户需转向第三方DDNS服务

《TP-LinkPDDNS服将于务6月30日正式停运:用户需转向第三方DDNS服务》近期,路由器制造巨头普联(TP-Link)在用户群体中引发了一系列重要变动,上个月,公司发出了一则通知,明确要求所... 路由器厂商普联(TP-Link)上个月发布公告要求所有用户必须完成实名认证后才能继续使用普联提供的 D

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查