2025-04-16-Wed-T-Java项目-商城项目学习
1.分布式基础(全栈开发篇)
- 架构图

1.1 项目介绍
1.1.1 项目背景
1)电商模式
市面上有5 种常见的电商模式B2B、B2C、C2B、C2C、O2O;
1、B2B 模式
B2B (Business to Business), 是指商家与商家建立的商业关系。如:阿里巴巴
2、B2C 模式
B2C (Business to Consumer), 就是我们经常看到的供应商直接把商品卖给用户,即“商对客”
模式,也就是通常说的商业零售,直接面向消费者销售产品和服务。如:苏宁易购、京东、
天猫、小米商城
3、C2B 模式
C2B (Customer to Business),即消费者对企业。先有消费者需求产生而后有企业生产,即先
有消费者提出需求,后有生产企业按需求组织生产
4、C2C 模式
C2C (Customer to Consumer) ,客户之间自己把东西放上网去卖,如:淘宝,闲鱼
5、O2O 模式
O2O 即Online To Offline,也即将线下商务的机会与互联网结合在了一起,让互联网成为线
下交易的前台。线上快速支付,线下优质服务。如:饿了么,美团,淘票票,京东到家
2)谷粒商城
谷粒商城是一个B2C 模式的电商平台,销售自营商品给客户。
1.1.2 项目架构图
项目微服务架构图

微服务划分图

1.1.3 项目技术&特色
前后分离开发,并开发基于vue 的后台管理系统
SpringCloud 全新的解决方案
应用监控、限流、网关、熔断降级等分布式方案全方位涉及
透彻讲解分布式事务、分布式锁等分布式系统的难点
分析高并发场景的编码方式,线程池,异步编排等使用
压力测试与性能优化
各种集群技术的区别以及使用
CI/CD 使用
1.1.4 业务基础概念
SPU与SKU
SPU: Standard Product Unit(标准化产品单元)
SPU是商品信息聚合的最小单位, 是一组可复用, 易于检索的标准化信息的集合, 该集合描述了一个产品的特性
SKU: Stock Keeping Unit (库存量单位)
SKU是库存进出量的基本单元, 可以是件, 盒, 托盘等为单位. SKU这是对大型连锁超市(配送中心)物流管理的一个必要的方法. 现在已经被引申为产品统一编号的简称, 每种产品均对应唯一的SKU号.
1.2 分布式基础概念
1.2.1 微服务
微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自
己的进程中,并使用轻量级机制通信,通常是HTTP API。这些服务围绕业务能力来构建,
并通过完全自动化部署机制来独立部署。这些服务使用不同的编程语言书写,以及不同数据
存储技术,并保持最低限度的集中式管理。
简而言之:拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行。
1.2.2 集群&分布式&节点
集群是个物理形态,分布式是个工作方式。
只要是一堆机器,就可以叫集群,他们是不是一起协作着干活,这个谁也不知道;
《分布式系统原理与范型》定义:
“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
分布式系统(distributed system)是建立在网络之上的软件系统。
分布式是指将不同的业务分布在不同的地方。
集群指的是将几台服务器集中在一起,实现同一业务。
例如:京东是一个分布式系统,众多业务运行在不同的机器,所有业务构成一个大型的业
务集群。每一个小的业务,比如用户系统,访问压力大的时候一台服务器是不够的。我们就
应该将用户系统部署到多个服务器,也就是每一个业务系统也可以做集群化;
分布式中的每一个节点,都可以做集群。而集群并不一定就是分布式的。
节点:集群中的一个服务器
1.2.3 远程调用
在分布式系统中,各个服务可能处于不同主机,但是服务之间不可避免的需要互相调用,我
们称为远程调用。
SpringCloud 中使用HTTP+JSON 的方式完成远程调用

1.2.4 负载均衡

分布式系统中,A 服务需要调用B 服务,B 服务在多台机器中都存在,A 调用任意一个服务器均可完成功能。
为了使每一个服务器都不要太忙或者太闲,我们可以负载均衡的调用每一个服务器,提升网站的健壮性。
常见的负载均衡算法:
轮询:为第一个请求选择健康池中的第一个后端服务器,然后按顺序往后依次选择,直
到最后一个,然后循环。最小连接:优先选择连接数最少,也就是压力最小的后端服务器,在会话较长的情况下
可以考虑采取这种方式。散列:根据请求源的IP 的散列(hash)来选择要转发的服务器。这种方式可以一定程
度上保证特定用户能连接到相同的服务器。如果你的应用需要处理状态而要求用户能连接到
和之前相同的服务器,可以考虑采取这种方式。
1.2.5 服务注册/发现&注册中心
A 服务调用B 服务,A 服务并不知道B 服务当前在哪几台服务器有,哪些正常的,哪些服务
已经下线。解决这个问题可以引入注册中心;

如果某些服务下线,我们其他人可以实时的感知到其他服务的状态,从而避免调用不可用的服务
1.2.6 配置中心

每一个服务最终都有大量的配置,并且每个服务都可能部署在多台机器上。我们经常需要变
更配置,我们可以让每个服务在配置中心获取自己的配置。
配置中心用来集中管理微服务的配置信息
1.2.7 服务熔断&服务降级
在微服务架构中,微服务之间通过网络进行通信,存在相互依赖,当其中一个服务不可用时,有可能会造成雪崩效应。要防止这样的情况,必须要有容错机制来保护服务。

1)服务熔断
a. 设置服务的超时,当被调用的服务经常失败到达某个阈值,我们可以开
启断路保护机制,后来的请求不再去调用这个服务。本地直接返回默认
的数据
2)服务降级
a. 在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业
务降级运行。降级:某些服务不处理,或者简单处理【抛异常、返回NULL、
调用Mock 数据、调用Fallback 处理逻辑】。
1.2.8 API 网关
在微服务架构中,API Gateway 作为整体架构的重要组件,它抽象了微服务中都需要的公共
功能,同时提供了客户端负载均衡,服务自动熔断,灰度发布,统一认证,限流流控,日
志统计等丰富的功能,帮助我们解决很多API 管理难题。

1.3 环境搭建
1.3.1 安装linux 虚拟机
下载&安装VirtualBox https://www.virtualbox.org/,主机需要开启CPU 虚拟化
- 下载&安装Vagrant:用于快速创建虚拟机
- https://app.vagrantup.com/boxes/search Vagrant 官方镜像仓库
- https://www.vagrantup.com/downloads.html Vagrant 下载
在cmd窗口输入vagrant, 如果出现命令提示,说明安装成功
1 | 打开window cmd 窗口,运行vagrant init centos/7,即可初始化一个centos7 系统 |
- vagrant 其他常用命令
1 | vagrant ssh # 自动使用vagrant 用户连接虚拟机。 |
https://www.vagrantup.com/docs/cli/init.html Vagrant 命令行
默认虚拟机的ip 地址不是固定ip,开发不方便, 可以修改Vagrantfile (在init的文件夹下)
1 | Create a private network, which allows host-only access to the machine |
重新使用vagrant up (或者vagrant restart)启动机器即可。然后再vagrant ssh 连接机器
1 | 测试 |
默认只允许ssh 登录方式,为了后来操作方便,文件上传等,我们可以配置允许账号密码登录
Vagrant ssh 进去系统之后
vi /etc/ssh/sshd_config
修改PasswordAuthentication yes/no
重启服务service sshd restart
以后可以使用提供的ssh 连接工具直接连接
注意:VirtualBox 会与包括但不限于如下软件冲突,需要卸载这些软件,然后重启电脑;
冲突的软件:红蜘蛛,360,净网大师(有可能)等
修改linux 的yum 源
1)、备份原yum 源sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
2)、使用新yum 源sudo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
3)、生成缓存yum makecache
1.3.2 安装docker
Docker 安装文档:https://docs.docker.com/install/linux/docker-ce/centos/
1、卸载系统之前的docker
1 | sudo yum remove docker \ |
2、安装Docker-CE
- 安装必须的依赖
1 | sudo yum install -y yum-utils \ |
- 设置docker repo 的yum 位置
1 | 设置阿里docker镜像仓库地址 |
- 安装docker,以及docker-cli
1 | sudo yum install docker-ce docker-ce-cli containerd.io |
3、启动docker
1 | sudo systemctl start docker |
4、设置docker 开机自启
1 | sudo systemctl enable docker |
5、测试docker 常用命令,注意切换到root 用户下
https://docs.docker.com/engine/reference/commandline/docker/
6、配置docker 镜像加速
阿里云,容器镜像服务
针对Docker 客户端版本大于1.10.0 的用户
您可以通过修改daemon 配置文件/etc/docker/daemon.json 来使用加速器
1 | sudo mkdir -p /etc/docker |
1.3.3 docker 安装mysql
1、下载镜像文件
1 | docker pull mysql:5.7 |
2、创建实例并启动
1 | docker run -p 3306:3306 --name mysql \ |
1 | 参数说明: |
1 | --restart=always # docker 重启时容器自启动 |
1 | MySQL 配置 |
3、通过容器的mysql 命令行工具连接
1 | docker exec -it mysql mysql -uroot -proot |
4、设置root 远程访问
1 | grant all privileges on *.* to 'root'@'%' identified by 'root' with grant option; |
5、进入容器文件系统
1 | docker exec -it mysql /bin/bash |
1.3.4 docker 安装redis
1、下载镜像文件
1 | docker pull redis |
2、创建实例并启动
1 | mkdir -p /mydata/redis/conf |
redis 自描述文件:
https://raw.githubusercontent.com/antirez/redis/4.0/redis.conf
3、使用redis 镜像执行redis-cli 命令连接
1 | docker exec -it redis redis-cli |
1 | # 防火墙操作 |
1.3.5 开发环境统一
1、Maven
1 | 配置阿里云镜像 |
2、Idea&VsCode
idea 安装lombok、mybatisx 插件
Vscode 安装开发必备插件
1 | Vetur —— 语法高亮、智能感知、Emmet 等 |
3、安装配置git
1、下载git;https://git-scm.com
2、配置git,进入git bash
配置用户名
git config –global user.name “username” //(名字)
配置邮箱
git config –global user.email “username@email.com“ //(注册账号时用的邮箱)
3、配置ssh 免密登录
https://gitee.com/help/articles/4181#article-header0
进入git bash;使用:ssh-keygen -t rsa -C “xxxxx@xxxxx.com“命令。连续三次回车。
一般用户目录下会有
或者cat ~/.ssh/id_rsa.pub
登录进入gitee,在设置里面找到SSH KEY 将.pub 文件的内容粘贴进去
使用ssh -T git@gitee.com 测试是否成功即可
Git+码云教程https://gitee.com/help/articles/4104
4、逆向工程使用
1、导入项目逆向工程
2、下载人人开源后台管理系统脚手架工程
(1) 导入工程,创建数据库
(2) 修改工程shiro 依赖为SpringSecurity
(3) 删除部分暂时不需要的业务
3、下载人人开源后台管理系统vue 端脚手架工程
(1) vscode 导入前端项目
(2) 前后端联调测试基本功能
1.3.6 创建项目微服务
商品服务、仓储服务、订单服务、优惠券服务、用户服务
共同:
1)、web、openfeign
2)、每一个服务,包名com.atguigu.gulimall.xxx(product/order/ware/coupon/member)
3)、模块名:gulimall-coupon
1)、从gitee 初始化一个项目
运行nacos容器
1 | docker run -d --name nacos -p 8848:8848 --restart=always -e MODE=standalone -d nacos/nacos-server:1.3.2 |
- 服务发现
1 | /** |
要注意nacos集群所在的server,一定要关闭防火墙,否则容易出现各种问题。
搭建nacos集群,然后分别启动各个微服务,将它们注册到Nacos中。
1 | application: |
- 使用openfen
1)、引入open-feign
1 | <dependency> |
2)、编写一个接口,告诉SpringCLoud这个接口需要调用远程服务
修改“com.bigdata.gulimall.coupon.controller.CouponController”,添加以下controller方法:
1 |
|
新建“com.bigdata.gulimall.member.feign.CouponFeignService”接口
1 |
|
修改“com.bigdata.gulimall.member.GulimallMemberApplication”类,添加上”@EnableFeignClients”:
1 |
|
声明接口的每一个方法都是调用哪个远程服务的那个请求
3)、开启远程调用功能
com.bigdata.gulimall.member.controller.MemberController
1 |
|
- 配置中心
1)修改“gulimall-coupon”模块
添加pom依赖:
1 | <dependency> |
创建bootstrap.properties文件,该配置文件会优先于“application.yml”加载。
1 | spring.application.name=gulimall-coupon |
2)传统方式
为了详细说明config的使用方法,先来看原始的方式
创建“application.properties”配置文件,添加如下配置内容:
1 | coupon.user.name="zhangsan" |
修改“com.bigdata.gulimall.coupon.controller.CouponController”文件,添加如下内容:
1 |
|
启动“gulimall-coupon”服务:
访问:http://localhost:7000/coupon/coupon/test>
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587716583668.png)
这样做存在的一个问题,如果频繁的修改application.properties,在需要频繁重新打包部署。下面我们将采用Nacos的配置中心来解决这个问题。
3)nacos config
1、在Nacos注册中心中,点击“配置列表”,添加配置规则:
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587716911435.png)
DataID:gulimall-coupon
配置格式:properties
文件的命名规则为:${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
${spring.application.name}:为微服务名
${spring.profiles.active}:指明是哪种环境下的配置,如dev、test或info
${spring.cloud.nacos.config.file-extension}:配置文件的扩展名,可以为properties、yml等
2、查看配置:
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587717125580.png)
3、修改“com.bigdata.gulimall.coupon.controller.CouponController”类,添加“@RefreshScope”注解
1 |
|
这样都会动态的从配置中心读取配置.
4、访问:http://localhost:7000/coupon/coupon/test
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587717485283.png)
能够看到读取到了nacos 中的最新的配置信息,并且在指明了相同的配置信息时,配置中心中设置的值优先于本地配置。
4)Nacos支持三种配置加载方方案
Nacos支持“Namespace+group+data ID”的配置解决方案。
Namespace方案
通过命名空间实现环境区分
下面是配置实例:
1、创建命名空间:
“命名空间”—>“创建命名空间”:
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587718802109.png)
创建三个命名空间,分别为dev,test和prop
2、回到配置列表中,能够看到所创建的三个命名空间
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587718889316.png)
下面我们需要在dev命名空间下,创建“gulimall-coupon.properties”配置规则:
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587719108947.png)
3、访问:http://localhost:7000/coupon/coupon/test
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587721184218.png)
并没有使用我们在dev命名空间下所配置的规则,而是使用的是public命名空间下所配置的规则,这是怎么回事呢?
查看“gulimall-coupon”服务的启动日志:
1 | 2020-04-24 16:37:24.158 WARN 32792 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[gulimall-coupon] & group[DEFAULT_GROUP] |
**”gulimall-coupon.properties”**,默认就是public命名空间中的内容中所配置的规则。
4、指定命名空间
如果想要使得我们自定义的命名空间生效,需要在“bootstrap.properties”文件中,指定使用哪个命名空间:
1 | spring.cloud.nacos.config.namespace=a2c83f0b-e0a8-40fb-9b26-1e9d61be7d6d |
这个命名空间ID来源于我们在第一步所创建的命名空间
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587718802109.png)
5、重启“gulimall-coupon”,再次访问:http://localhost:7000/coupon/coupon/test
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587720311349.png)
但是这种命名空间的粒度还是不够细化,对此我们可以为项目的每个微服务module创建一个命名空间。
6、为所有微服务创建命名空间
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587720714101.png)
7、回到配置列表选项卡,克隆pulic的配置规则到coupon命名空间下
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587720883244.png)
切换到coupon命名空间下,查看所克隆的规则:
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587720963699.png)
8、修改“gulimall-coupon”下的bootstrap.properties文件,添加如下配置信息
1 | spring.cloud.nacos.config.namespace=7905c915-64ad-4066-8ea9-ef63918e5f79 |
这里指明的是,读取时使用coupon命名空间下的配置。
9、重启“gulimall-coupon”,访问:http://localhost:7000/coupon/coupon/test
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587721184218.png)
DataID方案
通过指定spring.profile.active和配置文件的DataID,来使不同环境下读取不同的配置,读取配置时,使用的是默认命名空间public,默认分组(default_group)下的DataID。
默认情况,Namespace=public,Group=DEFAULT GROUP,默认Cluster是DEFAULT
Group方案
通过Group实现环境区分
实例:通过使用不同的组,来读取不同的配置,还是以上面的gulimall-coupon微服务为例
1、新建“gulimall-coupon.properties”,将它置于“tmp”组下
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587721616021.png)
2、修改“bootstrap.properties”配置,添加如下的配置
1 | spring.cloud.nacos.config.group=tmp |
3、重启“gulimall-coupon”,访问:http://localhost:7000/coupon/coupon/test
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587721844449.png)
5)同时加载多个配置集
当微服务数量很庞大时,将所有配置都书写到一个配置文件中,显然不是太合适。对此我们可以将配置按照功能的不同,拆分为不同的配置文件。
如下面的配置文件:
1 | server: |
我们可以将,
数据源有关的配置写到一个配置文件中:
1 | spring: |
和框架有关的写到另外一个配置文件中:
1 | mybatis-plus: |
也可以将上面的这些配置交给nacos来进行管理。
实例:将“gulimall-coupon”的“application.yml”文件拆分为多个配置,并放置到nacos配置中心
1、创建“datasource.yml”,用于存储和数据源有关的配置
1 | spring: |
在coupon命名空间中,创建“datasource.yml”配置
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587722798375.png)
2、将和mybatis相关的配置,放置到“mybatis.yml”中
1 | mybatis-plus: |
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587722710432.png)
3、创建“other.yml”配置,保存其他的配置信息
1 | server: |
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587722998265.png)
现在“mybatis.yml”、“datasource.yml”和“other.yml”共同构成了微服务的配置。
4、修改“gulimall-coupon”的“bootstrap.properties”文件,加载“mybatis.yml”、“datasource.yml”和“other.yml”配置
1 | spring.cloud.nacos.config.extension-configs[0].data-id=mybatis.yml |
“spring.cloud.nacos.config.ext-config”已经被废弃,建议使用“spring.cloud.nacos.config.extension-configs”
5、注释“application.yml”文件中的所有配置
6、重启“gulimall-coupon”服务,然后访问:http://localhost:7000/coupon/coupon/test
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587724212905.png)
7、访问:http://localhost:7000/coupon/coupon/list,查看是否能够正常的访问数据库
.rar.160/Guli Mall/文档/三阶段大纲md/images/1587724350548.png)
小结:
1)、微服务任何配置信息,任何配置文件都可以放在配置中心;
2)、只需要在bootstrap.properties中,说明加载配置中心的哪些配置文件即可;
3)、@Value, @ConfigurationProperties。都可以用来获取配置中心中所配置的信息;
4)、配置中心有的优先使用配置中心中的,没有则使用本地的配置。
2)、创建各个微服务项目
1)、了解人人开源项目,快速搭建后台脚手架
2)、修改代码调整为我们的业务逻辑
3)、创建各个微服务以及数据库
2. 分布式高级 (微服务架构篇)
2.1 Elasticsearch
2.1.1 基本概念
- index
动词: 相当于mysl中的insert
名词: 相当于mysql中的database
- type
在index中,可以定义一个或多个类型
类似于Mysql中的table, 每一种类型的数据放在一起
- document
保存在某个index下, 某个type的一个数据. document是json格式的
2.2 Docker 镜像安装
1 | # 安装Elasticsearch |
2.3 初步检索
_cat
1 | GET |
索引与文档json
1 | PUT or POST # 创建和更新 |
批量操作
1 | POST customer/external/_bulk |
Nginx镜像安装
1 | # 先启动一个nginx镜像,用于复制配置文件 |
2.4. 压力测试
指标:
响应时间
HPS: 每秒单击次数 Hits Per Second
TPS: 系统每秒处理交易数
QPS: 系统每秒处理查询次数
- 如果某些业务有且仅有一个请求连接, 则QPS=TPS=HPS
- TPS衡量整个业务流程, QPS衡量接口查询次数, HPS描述对服务器的单击请求
TPS,QPS,HPS越大越好
一般情况下:
- 金融行业: 1000TPS~50000TPS, 普通业务,不包含互联网业务
- 保险行业: 100TPS~100000TPS, 不包含互联网业务
- 制造业: 10TPS ~ 5000TPS
- 互联网电子商务: 100000TPS ~ 1000000TPS
- 互联网中型网站: 1000TPS ~ 50000TPS
- 互联网小型网站: 500TPS ~ 10000TPS

缓存与分布式锁
2.5 RabitMQ

1 | docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 ----restart=always rabbitmq:management |
RabbitMQ整合Spring Boot
- 引入依赖
1 | <!--引入RabbitMQ : AMQP(高级消息队列协议) Advanced--> |
依赖引入之后,RabbitAutoConfiguration就会自动生效。
给容器中自动配置: RabbitTemplate, AmqpAdmin, CachingConnectionFactory等
- application yaml配置
1 | spring: |
启动类添加注解:
1 |
- 测试RabbitMQ
1 |
|
- 监听消息
- 类 + 方法上
1 | // 必须开启@EnableRabbit, 注解需要再组件类或其内部的方法中 |
- 方法上
1 | //必须开启@EnableRabbit, 只能标注在方法上 |
RabbitMQ消息确认机制 - 可靠抵达

发送端(producer)
- confirmCallback: exchange接收到后会触发
- returnCallback:queue接受到之后会触发
接收端(consumer)
- ack:consumer接收到之后会触发

confirmCallback使用
1 | # 1. 配置yaml |
1 | // 2. 配置RabbitTemplate |
retrunCallback使用
1 | # 1. yaml 配置 |
1 | /** |
ack消息确认机制使用

1 | # 1. yaml配置 |
1 | // 2. 手动确认接受 |
2.6 订单业务
2..6.1 订单中心
电商系统涉及到3流,分别是信息流,资金流、物流。而订单系统作为中枢将三者有机集合起来。
订单模块是电商系统的枢纽,在订单这个环节上需求获取多个模块的数据和信息,同时对这些信息进行加工处理后流向下个环节。这一系列就构成了订单的信息流通。


