【SpringCloud Alibaba】(二)微服务环境搭建

news2024/11/25 21:46:04

1. 项目流程搭建

整个项目主要分为 用户微服务、商品微服务和订单微服务,整个过程模拟的是用户下单扣减库存的操作。这里,为了简化整个流程,将商品的库存信息保存到了商品数据表,同时,使用商品微服务来扣减库存。小伙伴们在实现时,也可以将商品库存信息单独开发一个微服务模块,主体逻辑和将库存信息放在商品微服务进行管理是一样的。各服务之间的调用流程如下:
在这里插入图片描述
用户微服务、商品微服务和订单微服务的整体流程为:用户通过客户端调用订单微服务的提交订单的接口后,订单微服务会分别调用用户微服务和商品微服务的接口来查询用户信息和商品信息,并校验商品库存是否充足,如果商品库存充足的话,就会保存订单。并且会调用商品微服务的扣减库存的接口来扣减库存

2. 技术选型

整个项目采用 SpringCloud Alibaba 技术栈实现,主要的技术选型如下所示:

  • 持久层框架:MyBatis、MyBatis-Plus
  • 微服务框架:SpringCloud Alibaba
  • 消息中间件:RocketMQ
  • 服务治理与服务配置:Nacos
  • 负载均衡组件:Ribbon
  • 远程服务调用:Fegin
  • 服务限流与容错:Sentinel
  • 服务网关:SpringCloud-Gateway
  • 服务链路追踪:Sleuth + ZipKin
  • 分布式事务:Seata
  • 数据存储:MySQL+ElasticSearch

3. 模块划分

为了方便开发和维护,同时为了模块的复用性,整体项目在搭建时,会将用户微服务、商品微服务和订单微服务放在同一个 Maven 父工程下,作为父工程的子模块,同时,将用户微服务、商品微服务和订单微服务都会使用的 JavaBean 单独作为一个 Maven 模块,以及各服务都会使用的工具类单独作为一个 Maven 模块

在这里插入图片描述
其中各模块的说明如下所示:

  • shop-springcloud-alibaba:Maven 父工程。
  • shop-bean:各服务都会使用的 JavaBean 模块,包含实体类、Dto、Vo 等 JavaBean。
  • shop-utils:各服务都会使用的工具类模块。
  • shop-order:订单微服务。
  • shop-product:商品微服务。
  • shop-user:用户微服务

4. 代码地址

代码码云地址

其中,数据库文件位于 db 文件夹下。

5. 模块开发

代码已托管到码云,这里只贴部分代码。

5.1 创建 maven 父工程

在IDEA中创建 Maven 工程,名称为 shop-springcloud-alibaba,创建后在项目的 pom.xml 文件中添加
StringBoot 与 SpringCloud alibaba 相关的配置,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/>
    </parent>
    <packaging>pom</packaging>
    <groupId>com.zzc</groupId>
    <artifactId>shop-springcloud-alibaba</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shop-springcloud-alibaba</name>
    <description>shop-springcloud-alibaba</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
        <logback.version>1.1.7</logback.version>
        <slf4j.version>1.7.21</slf4j.version>
        <common.logging>1.2</common.logging>
        <fastjson.version>1.2.51</fastjson.version>
        <mybatis.version>3.4.6</mybatis.version>
        <mybatis.plus.version>3.4.1</mybatis.plus.version>
        <mysql.jdbc.version>8.0.19</mysql.jdbc.version>
        <druid.version>1.1.10</druid.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

5.2 创建工具类模块

在父工程下创建工具类模块 shop-utils,作为整个项目的通用工具类模块。工具类模块的总体结构如下所示:
在这里插入图片描述
代码结构说明:

  1. HttpCode:HTTP 状态码封装类
  2. RestCtrlExceptionHandler:全局异常捕获类
  3. md5 包:通用 MD5 与密码加密类
  4. Result:数据响应类
  5. id 包:使用雪花算法生成 Id

5.3 创建其它微服务模块

5.3.1 创建实体类模块

在父工程下创建实体类模块 shop-bean,作为整个项目的通用实体类模块

shop-bean 模块的依赖相对来说就比较简单了,只需要依赖 shop-utils 模块即可。在 shop-bean 模块的 pom.xml 文件中添加如下配置:

<dependency>
    <groupId>com.zzc</groupId>
    <artifactId>shop-utils</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

5.3.2 创建三大微服务并完成交互

对于用户微服务、商品微服务和订单微服务来说,每个服务占用的端口和访问的基础路径是不同的,这里就将每个服务占用的端口和访问的基础路径整理成下表所示:

服务名称项目名称占用端口访问的基础路径备注
用户微服务shop-user8060/user用户的增删改查
商品微服务shop-product8070/product商品的增删改查
订单微服务shop-order8080/order订单的增删改查

创建微服务

创建名称为 shop-user 的 Maven 项目,由于我们在前面的文章中,已经完成了对项目整体结构的搭建,所以,在 shop-user 的 pom.xml 文件里添加如下依赖即可:

<dependency>
    <groupId>com.zzc</groupId>
    <artifactId>shop-bean</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

shop-productshop-order 微服务与 shop-user 类似,只是配置文件 application.yml 配置端口、访问路径不同。

6. 订单微服务下单接口

这里重点看看 shop-order 的下单接口:

@Override
@Transactional(rollbackFor = Exception.class)
public void saveOrder(OrderParamVo orderParamVo) {
    if (orderParamVo.isEmpty()){
        throw new RuntimeException("参数异常: " + JSONObject.toJSONString(orderParamVo));
    }
    User user = restTemplate.getForObject("http://localhost:8060/user/get/" + orderParamVo.getUserId(), User.class);
    if (user == null){
        throw new RuntimeException("未获取到用户信息: " + JSONObject.toJSONString(orderParamVo));
    }
    Product product = restTemplate.getForObject("http://localhost:8070/product/get/" + orderParamVo.getProductId(), Product.class);
    if (product == null){
        throw new RuntimeException("未获取到商品信息: " + JSONObject.toJSONString(orderParamVo));
    }
    if (product.getProStock() < orderParamVo.getCount()){
        throw new RuntimeException("商品库存不足: " + JSONObject.toJSONString(orderParamVo));
    }
    Order order = new Order();
    order.setAddress(user.getAddress());
    order.setPhone(user.getPhone());
    order.setUserId(user.getId());
    order.setUsername(user.getUsername());
    order.setTotalPrice(product.getProPrice().multiply(BigDecimal.valueOf(orderParamVo.getCount())));
    baseMapper.insert(order);
    OrderItem orderItem = new OrderItem();
    orderItem.setNumber(orderParamVo.getCount());
    orderItem.setOrderId(order.getId());
    orderItem.setProId(product.getId());
    orderItem.setProName(product.getProName());
    orderItem.setProPrice(product.getProPrice());
    orderItemMapper.insert(orderItem);
    Result<Integer> result = restTemplate.getForObject("http://localhost:8070/product/update_count/" + orderParamVo.getProductId() + "/" + orderParamVo.getCount(), Result.class);
    if (result.getCode() != HttpCode.SUCCESS){
        throw new RuntimeException("库存扣减失败");
    }
    log.info("库存扣减成功");
}

saveOrder() 方法的实现中,实现的主要逻辑如下:

  1. 判断 orderParams 封装的参数是否为空,如果参数为空,则抛出参数异常。
  2. 通过 RestTemplate 调用用户微服务获取用户的基本信息,如果获取的用户信息为空,则抛出未获
    取到用户信息的异常。
  3. 通过 RestTemplate 调用商品微服务获取商品的基本信息,如果获取的商品信息为空,则抛出未获
    取到商品信息的异常。
  4. 判断商品的库存是否小于待扣减的商品数量,如果商品的库存小于待扣减的商品数量,则抛出商品
    库存不足的异常。
  5. 如果 orderParams 封装的参数不为空,并且获取的用户信息和商品信息不为空,同时商品的库存
    充足,则创建订单对象保存订单信息,创建订单条目对象,保存订单条目信息。
  6. 调用商品微服务的接口扣减商品库存

在上述实现的过程中,存在一个很明显的问题:那就是将用户微服务所在的IP和端口,以及商品微服务所在的IP和端口硬编码到订单微服务的代码中了。这样的做法存在着非常多的问题

硬编码的问题

如果将用户微服务和商品微服务所在的IP地址和端口号硬编码到订单微服务中,会存在非常多的问题,其中,最明显的问题有三个,如下所示。

  1. 如果用户微服务和商品微服务的IP地址或者端口号发生了变化,则订单微服务将变得不可用,需要
    对同步修改订单微服务中调用用户微服务和商品微服务的IP地址和端口号。
  2. 如果系统中提供了多个用户微服务和商品微服务,则无法实现微服务的负载均衡功能。
  3. 如果系统需要支持更高的并发,需要部署更多的用户微服务和商品微服务以及订单微服务,如果将用户微服务和商品微服务的IP地址和端口硬编码到订单微服务,则后续的维护会变得异常复杂。

所以,在微服务开发的过程中,需要引入服务治理功能,实现微服务之间的动态注册与发现。

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

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

相关文章

【简单认识MySQL主从复制与读写分离】

文章目录 一、MySQL主从复制1、配置主从复制的原因&#xff1a;2、主从复制原理1、 MySQL的复制类型2、 MySQL主从复制的工作过程;1、 MySQL主从复制延迟2、优化方案&#xff1a;3、 MySQL 有几种同步方式&#xff1a; 三种4、异步复制&#xff08;Async Replication&#xff0…

【初始C语言】多种输入格式的优劣

多种输入格式的优劣【初始C语言】 一.多种输入格式的不同&#xff08;只针对输入字符&#xff0c;字符串&#xff09;1.scanf&#xff08;"%s",字符数组名&#xff09;2.scanf("%[^\n]s",字符数组名)3.gets(字符数组名)4.fgets&#xff08;字符数组名,规定…

光耦参数设置

2.1发光二极管电阻的选择 数据手册中&#xff0c;IF是发光二极管的允许最大正向电流&#xff0c;值是80mA。这是需要考虑的第一个条件。 再看第二张图&#xff0c;VF是二极管上的电压&#xff0c;图中给出&#xff0c;当IF是10mA的时候&#xff0c;VF的值最大是1.4V。这是需要考…

【python工具】html中表格转化为excel

背景 大家在实际的工作中可能会遇到这样的场景,查看某个统计的页面数据,其中一些数据是表格形式展示的,比如这是国家统计局关于人口统计的数据: 你想将表格内容下载下来根据自己的需要进行二次加工,但是页面没有提供下载功能或者需要你登陆才能下载。那么重点来了~~ 操…

初识 Spring (存储和获取 bean)

目录 初识 Spring总结 DI&#xff08;依赖注入&#xff09;Spring 项目的创建创建一个 Maven 项目添加 Spring 框架支持添加启动类 存储 bean 对象创建 bean将 bean 注册到容器中 获取并使用 bean 对象获取 bean 的方法一获取 bean 的方法二获取 bean 的方法三 ApplicationCont…

【雕爷学编程】Arduino动手做(55)--DHT11温湿度传感器模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

Cesium态势标绘专题-位置点(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

RocketMQ教程-(4)-领域模型-消费者分组ConsumerGroup

定义​ 消费者分组是 Apache RocketMQ 系统中承载多个消费行为一致的消费者的负载均衡分组。 和消费者不同&#xff0c;消费者分组并不是运行实体&#xff0c;而是一个逻辑资源。在 Apache RocketMQ 中&#xff0c;通过消费者分组内初始化多个消费者实现消费性能的水平扩展以…

练习——动态内存分配的笔试题

今天我们分享几道经典的笔试题&#xff0c;做完直接变成陈泽 第一题 ~~ --------------------------------------------------------------------------------------------------~~ void GetMemory(char* p) {p (char*)malloc(100); } void Test(void) {char* str NULL;Get…

计算机网络第一章概述

第1章 网络概述 因特网(Internet) 是世界上最大的互连网络【小写i的internet是通用名词&#xff0c;互连的网络都叫internet】 因特网的前身是1969年创建的第一个分组交换网&#xff1a;ARPANT 普通用户如何接入因特网&#xff1f; 通过ISP接入因特网。ISP可以从因特网管理…

C/C++ 程序 IDE 开发工具 CLion

下载地址&#xff1a; https://www.jetbrains.com/clion/ https://www.jetbrains.com/clion/ 下载地址&#xff1a; https://www.jetbrains.com/clion/download/ https://www.jetbrains.com/clion/download/ 历史版本&#xff08;老版本&#xff09;下载地址&#xff1a; h…

基于RASC的keil电子时钟制作(瑞萨RA)(4)----使用串口进行程序烧写

基于RASC的keil电子时钟制作4_使用串口进行程序烧写 概述硬件准备视频教程软件准备hex文件准备UART串口与瑞萨开发板进行接线烧录 概述 本篇文章主要介绍如何使用UART串口烧写程序到瑞萨芯片&#xff0c;并以实际项目进行演示。 硬件准备 首先需要准备一个开发板&#xff0c…

Docker 续

Docker 续 一、Docker 网络1.1 Docker 网络实现原理1.2 Docker 的网络模式1.2.1 Docker 网络模式分类 1.3 如何创建各类网络模式1.4 host模式1.5 container模式1.6 none模式1.7 bridge模式1.8 自定义网络 二、资源控制2.1 Cgroup2.2 CPU 资源控制2.2.1 设置CPU使用率上限2.2.2 …

Attention详解(自用)

encoder-decoder 分心模型&#xff1a;没有引入注意力的模型在输入句子比较短的时候问题不大&#xff0c;但是如果输入句子比较长&#xff0c;此时所有语义完全通过一个中间语义向量来表示&#xff0c;单词自身的信息已经消失&#xff0c;可想而知会丢失很多细节信息&#xff0…

科技UI图标的制作

科技UI图标的制作&#xff0c;效果图如下&#xff1a; 一、新建合成 1、新建合成&#xff0c;命名为合成1&#xff0c;参数设置如下&#xff1a; 2、新建纯色&#xff0c;命名为分形 二、添加分形杂色 1、添加分形杂色 为纯色层“分形”&#xff0c;添加分形杂色&#xff0c…

Oracle根据日志执行相应的存过处理逻辑

背景: 项目上有两个不同的MPP数据库(HIVE、oceanbase),目前的问题是需要把hive的数据迁移到ob中。数据体量大于4000亿,文件容量有300T,hive作为计算库(大于120节点的集群)把结果数据计算出,存放在DWD层,hive的表有近40张,大部分是大宽表(大于100个字段),里面字段…

从C到C++ | C++入门(三)

目录 内联函数 auto 关键字 范围for 指针空值nullptr 内联函数 以inline修饰的函数叫内联函数&#xff0c;编译时C编译器会在调用函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;可提升程序的运行效率。 例子&#xff1a; #include <iostream> …

使用JMeter进行接口测试教程

安装 使用JMeter的前提需要安装JDK&#xff0c;需要JDK1.7以上版本目前在用的是JMeter5.2版本&#xff0c;大家可自行下载解压使用 运行 进入解压路径如E: \apache-jmeter-5.2\bin&#xff0c;双击jmeter.bat启动运行 启动后默认为英文版本&#xff0c;可通过Options – Ch…

RISCV - 2 “Zicsr“, CSR Instructions

RISCV - 2 “Zicsr“, CSR Instructions 1 CSR Instructions2 CSR Access Ordering3 CSR指令集类型 CSR&#xff1a;Control and Status Register RISCV - 1 RV32/64G指令集清单 RISC-V defines a separate address space of 4096 Control and Status registers associated w…

Java集合之Map

HashMap集合 HashMap的特点 HashMap的常用方法 ①.put(K key, V value) 将键&#xff08;key&#xff09;/值&#xff08;value&#xff09;映射存放到Map集合中 public class Test {public static void main(String[] args) {HashMap<String, Integer> map new Hash…