深入浅出 -- 系统架构之微服务中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 的工作就完成了,大家可以按照自己的业务愉快的撸码了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/805577.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谁在投资“元素周期表”? 顶级芯片制造商“军备竞赛”

有色和商品基金的大买家何在 投资A股&#xff0c;有时候投资的也是一种“玄妙”的境界。 你需要复习金融知识、复习经济知识&#xff0c;复习科技知识&#xff0c;学习财政学、学习人口学、学习传染病学。 但这些可能还不够。 你能想象么有朝一日&#xff0c;你会回头复习中…

Flask项目如何在测试环境和生产环境部署上线

前言 最近在使用Flask框架&#xff0c;写一个小项目&#xff0c;在项目部署启动后&#xff0c;出现了以下这段提示&#xff0c;这段提示的意思是&#xff0c;该启动方式适用于开发环境中&#xff0c;生产环境要使用WSGI服务器。 WARNING: This is a development server. Do no…

OSCP靶场--Zino

OSCP靶场–Zino 考点(CVE-2019-9581 RCE 定时任务脚本可写提权) 1.nmap扫描 ##┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.173.64 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-10 04:18 EDT Nmap scan report for 192.…

自定义注解进行数据转换

前言&#xff1a; Java注解是一种元数据机制&#xff0c;可用于方法&#xff0c;字段&#xff0c;类等程序上以提供关于这些元素的额外信息。 以下内容是我自己写的一个小测试的demo,参考该文章进行编写&#xff1a;https://blog.csdn.net/m0_71621983/article/details/1318164…

【linux】基础IO(四)

在上一篇基础IO中我们主要讲述了文件再磁盘中的存储&#xff0c;当然我们说的也都只是预备知识&#xff0c;为这一篇的文件系统进行铺垫。 目录 搭文件系统的架子&#xff1a;填补细节&#xff1a;inode&#xff1a;datablock[]: 更上层的理解&#xff1a; 搭文件系统的架子&a…

uniapp 2.0可视化工具:创建与管理Vue文件的实践之旅

引言 在前端开发领域中&#xff0c;Vue以其简洁、易上手的特点&#xff0c;受到了广大开发者的青睐。随着uniapp的不断发展&#xff0c;越来越多的开发者开始利用uniapp的可视化工具来创建和管理Vue文件&#xff0c;以提高开发效率。本文将详细介绍如何使用uniapp 2.0可视化工…

bytetrack复现

一,环境安装 创建虚拟环境 conda create -n bytetrack python=3.8 安装requirements pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple 可能报错,解决办法,安装numpy 安装 pytorch pip install torch==1.12.0+cu113 torchvision==0.13.0+cu1…

H5动效开发之CSS3动画

动画效果是情感设计的重要手段,在H5开发中,实现动效需要综合利用 JavaScript、CSS(3)、SVG、Canvas 等多种 Web 技术手段才能开发出动人的网页动态效果。 接下来,我们把重心放在 CSS3 动画上面,因为 CSS3 在现如今的网页动效开发中占据着最为重要的一席,作为老大哥 CSS 的…

基于SSM+Jsp+Mysql的超市管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

SuperMap GIS基础产品FAQ集锦(202403)

一、SuperMap GIS基础产品桌面GIS-FAQ集锦 问题1&#xff1a;【iDesktop】安装了idesktop 11i&#xff0c;现想进行插件开发&#xff0c;根据安装指南安装SuperMap.Tools.RegisterTemplate.exe&#xff0c;运行多次均失败 【问题原因】该脚本是之前老版本针对VS2010写的&…

uniapp开发小程序,点击右上角<重新进入小程序>进行刷新时,设置开屏加载页面

一、需求及问题 问题&#xff1a;使用uniapp开发小程序时&#xff0c;有【学生端】和【企业端】两个入口&#xff0c;一进入小程序默认进入【学生端首页】&#xff0c;但是当前处于【企业端】时&#xff0c;点击右上角<重新进入小程序>进行刷新时&#xff0c;页面默认进…

国内如何实现GPT升级付款

本来想找国外的朋友代付的&#xff0c;但是他告诉我他的信用卡已经被绑定了他也升级了所以只能自己想办法了。就在一位博主下边发现了这个方法真的可以。只是需要与支付宝验证信息。刚开始不敢付款害怕被骗哈哈&#xff0c;我反诈骗意识绝对杠杠的 该方法就是我们办理一张虚拟…

每天五分钟深度学习PyTorch:面对Tensorflow,为何我选择PyTorch

这篇专栏文章不是为了挑起tenserflow和pytorch中哪个更好&#xff0c;众所周知tensorflow诞生以来&#xff0c;已经成为最流行的深度学习框架&#xff0c;可以说github中大多数的深度学习代码实现是以tensorflow实现的&#xff0c;也就是说资源众多&#xff0c;社区强大&#x…

还不会免费将PDF转为Word?赶快试试这3种工具!

PDF文档格式转换是高频且刚需的办公需求&#xff0c;虽然很简单&#xff0c;但其实绝大部分人找不到合适的工具。 将PDF免费转为Word的方法有很多&#xff0c;这里主要介绍三种工具。 第一种使用最常见的Word软件&#xff0c;第二种使用免费转换网站pdf2doc&#xff0c;第三种…

AI论文精读之CSPNet—— 一种加强CNN模型学习能力的主干网络

目录 一、论文摘要部分 二、提出背景 三、本文的方法 3.1 DenseNet 3.2 Cross Stage Partial DenseNet 3.3 引入 partial dense block及partial transition layer的目的 3.3.1 partial dense block 3.3.2 partial transition layer 3.4 将CSPNet应用到其他结构中 3.5 E…

比nestjs更优雅的ioc:跨模块访问资源

使用ts的最佳境界&#xff1a;化类型于无形 在项目中使用ts可以带来类型智能提示与校验的诸多好处。同时&#xff0c;为了减少类型标注&#xff0c;达到化类型于无形的效果&#xff0c;CabloyJS引入了ioc和依赖查找的机制。在上一篇文章中&#xff0c;我们创建了一个业务模块t…

基于Java+SpringBoot+Vue文学名著分享系统(源码+文档+部署+讲解)

一.系统概述 随着世界经济信息化、全球化的到来和互联网的飞速发展&#xff0c;推动了各行业的改革。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、动态的、交互友好的、高效的文学名著分享系统。当前的信息管理…

稀碎从零算法笔记Day45-LeetCode:电话号码的字母组合

题型&#xff1a;映射、回溯算法、递归 链接&#xff1a;17. 电话号码的字母组合 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出…

人工智能分类算法概述

文章目录 人工智能主要分类算法决策树随机森林逻辑回归K-均值 总结 人工智能主要分类算法 人工智能分类算法是用于将数据划分为不同类别的算法。这些算法通过学习数据的特征和模式&#xff0c;将输入数据映射到相应的类别。分类算法在人工智能中具有广泛的应用&#xff0c;如图…

网工内推 | 安全运维、服务工程师,软考中级、CISP优先,六险一金

01 华成峰科技 招聘岗位&#xff1a;安全运维工程师 职责描述&#xff1a; 1、负责安全产品的运维管理&#xff0c;包括设备升级变更、策略配置优化、设备巡检等&#xff1b; 2、负责7*24小时安全监控与应急响应&#xff0c;包括态势感知日志监测、安全事件分析及处置等&#…