[Java]微服务拆分
导入项目
本篇及后续的微服务学习都是基于Centos7系统下的Docker部署,因此需要准备:
- Centos7的环境
- SSH客户端
- 安装好Docker
- 会使用Docker
之前的学习, 导致虚拟机中存在黑马商城项目以及mysql数据库, 为了保持一致, 需要删除
- cd /root
- docker compose down
安装mysql
- 在课前资料提供好了MySQL的一个目录, 其中有MySQL的配置文件和初始化脚本:
- 我们将其复制到虚拟机的 /root 目录。如果 /root下已经存在 mysql 日录则删除旧的
- 新建一个通用网络
- 安装mysql
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/conf:/etc/mysql/conf.d \
-v /root/mysql/init:/docker-entrypoint-initdb.d \
--network hm-net \
mysql
- 远程连接mysql
- 账密: root/123
运行后端
- 在课前资料提供了一个hmall目录, 将其复制到你的工作空间,然后利用Idea打开
- 修改application-local.yaml文件, 配置自己的数据库IP地址
- 按下 ALT +8键打开services窗口,新增一个启动项, 在弹出窗口中鼠标向下滚动,找到 Spring Boot
- 目的就是让程序运行时读取local环境的配置文件
- 作用等同于修改下面的配置, 修改代码的话, 部署时要改回来, 麻烦
- 要把Mybatis的版本改为3.4.2, 不然上面的步骤会出现问题
- 启动服务并访问
运行前端
- 在课前资料中还提供了一个hmall-nginx的目录
- 其中就是一个nginx程序以及前端代码,将其复制到一个非中文、不包含特殊字符的目录下。
- 然后进入hmall-nginx目录,利用cmd启动即可, 双击exe启动关闭时不方便
- 访问前端
- http://localhost:18080/
- jack/123
认识微服务
单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署
优点:: 架构简单, 部署成本低
缺点: 团队协作成本高, 系统发布效率低, 系统可用性差
总结: 单体架构适合开发功能相对简单,规模较小的项目
comcat服务器的连接数是有限的, 随着并发请求量的上升, 整个系统的响应速度就会变慢
微服务架构,是服务化思想指导下的一套最佳实践架构方案。服务化,就是把单体架构中的功能模块拆分为多个独立项目
优势: 粒度小, 团队自治, 服务自治
劣势: 部署和运维的复杂度提高, 跨模块的任务难度提高
SpringCloud是目前国内使用最广泛的微服务框架。集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验
官网地址: https://spring.io/proiects/spring-cloudSpringCloud
SpringCloud基于SpringBoot实现了微服务组件的自动装配,从而提供了良好的开箱即用体验。但对于SpringBoot的版本也有要求:
服务拆分
熟悉黑马商城
核心业务包含用户模块, 购物车模块, 支付模块
服务拆分原则
什么时候拆分?
创业型项目: 先采用单体架构,快速开发,快速试错。随着规模扩大,逐渐拆分。
确定的大型项目: 资金充足,目标明确,可以直接选择微服务架构,避免后续拆分的麻烦。
怎么拆分?
- 从拆分目标来说,要做到:
高内聚: 每个微服务的职责要尽量单一,包含的业务相互关联度高、完整度高。
低耦合: 每个微服务的功能要相对独立,尽量减少对其它微服务的依赖。
- 从拆分方式来说,一般包含两种方式:
纵向拆分: 按照业务模块来拆分
横向拆分: 抽取公共服务,提高复用性
拆成什么样?
微服务的工程结构有两种: 独立Project 和 Maven聚合
- 独立Project结构的微服务工程适合超大工程, 各个服务绝对独立, 但是代码分散, 管理成本较高
- Maven聚合适合一般工程, 父工程下, 各个服务被划分为模块, 项目还是集中管理
拆分服务
拆分商品服务item-service
将hm-service中与商品管理相关功能拆分到一个微服务module中,命名为item-service
- 飞书文档: Docs
- 新建模块
- 拷贝依赖: 从hm-service中拷贝需要的依赖
<dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--数据库--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mybatis--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
- 创建启动类: 拷贝hmall-service的启动类, 进行修改
package com.hmall.item;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.hmall.item.mapper")
@SpringBootApplication
public class ItemApplication {public static void main(String[] args) {SpringApplication.run(ItemApplication.class, args);}
}
- 准备数据库: 真实项目中一般是独立服务独立mysql, 我们采用一个mysql独立database, 进行数据隔离
- 使用资料中提供的sql文件, 创建数据表并插入数据
- 注意要启动linux中的mysql服务
- 准备配置文件: 拷贝hmall-service的配置文件, 进行修改
server:port: 8081 #每个微服务运行在不同端口
spring:application:name: item-service #每个微服务对应一个名称profiles:active: dev #读取dev的配置datasource: #数据库配置url: jdbc:mysql://${hm.db.host}:3306/hm-item?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: ${hm.db.pw}
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto
logging: #日志配置level: #日志记录级别com.hmall: debugpattern: #日志日期格式dateformat: HH:mm:ss:SSSfile: #日志保存目录path: "logs/${spring.application.name}"
knife4j: #swagger配置enable: trueopenapi:title: 黑马商城商品管理接口文档description: "黑马商城商品管理接口文档"email: 123456@qq.comconcat: 王url: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources: # 指定扫描的包- com.hmall.item.controller
hm:db:host: 192.168.1.97 # 修改为你自己的虚拟机IP地址pw: 123 # 修改为docker中的MySQL密码
- 拷贝业务代码
- 先复制实体类, 再复制mapper, 再复制service, 再复制controller
- 代码报错都是因为导包的路径发生了变化, 删除后让idea重新导入
- ItemServiceImpl中要手动修改下包的路径
- 补充
- po是用来封装数据库数据的
- vo是返回给前端的
- dto是封装前端请求参数的
- 启动服务: 通过spring boot启动项启动服务, 快捷键 alt + 8
如果启动类没有出现在启动项面板, ,
- 可以刷新maven重试
- 或者手动添加
- 访问接口文档 http://localhost:8081/doc.html#/home
拆分购物车服务cart-service
将hm-service中与购物车有关的功能拆分到一个微服务module中,命名为cart-service
- 新建模块
- 拷贝依赖: 从item-service中拷贝需要的依赖
<dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--数据库--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mybatis--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
- 创建启动类: 拷贝hmall-service的启动类, 进行修改
package com.hmall.cart;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
public class CartApplication {public static void main(String[] args) {SpringApplication.run(CartApplication.class, args);}
}
- 准备数据库: 使用资料中提供的sql文件, 创建数据表并插入数据
- 准备配置文件: 拷贝item-service的配置文件, 进行修改
server:port: 8082 #每个微服务运行在不同端口
spring:application:name: cart-service #每个微服务对应一个名称profiles:active: dev #读取dev的配置datasource: #数据库配置url: jdbc:mysql://${hm.db.host}:3306/hm-cart?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: ${hm.db.pw}
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto
logging: #日志配置level: #日志记录级别com.hmall: debugpattern: #日志日期格式dateformat: HH:mm:ss:SSSfile: #日志保存目录path: "logs/${spring.application.name}"
knife4j: #swagger配置enable: trueopenapi:title: 黑马商城购物车管理接口文档description: "黑马商城购物车管理接口文档"email: 123456@qq.comconcat: 王url: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources: # 指定扫描的包- com.hmall.cart.controller
- 拷贝业务代码
- 先复制实体类, 再复制mapper, 再复制service, 再复制controller
- 代码报错都是因为导包的路径发生了变化, 删除后让idea重新导入
- CartServiceImpl中耦合了其他模块的功能, 暂时注释掉
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {// 拆分微服务后, 无法注入其他模块的service使用了// private final IItemService itemService;... ...@Overridepublic List<CartVO> queryMyCarts() {// 1.查询我的购物车列表// todo: UserContext.getUser() => 写死1 ,待优化List<Cart> carts = lambdaQuery().eq(Cart::getUserId,1L ).list();... ...}private void handleCartItems(List<CartVO> vos) {// todo 待优化
// // 1.获取商品id
// Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
// // 2.查询商品
// List<ItemDTO> items = itemService.queryItemByIds(itemIds);
// if (CollUtils.isEmpty(items)) {
// return;
// }
// // 3.转为 id 到 item的map
// Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
// // 4.写入vo
// for (CartVO v : vos) {
// ItemDTO item = itemMap.get(v.getItemId());
// if (item == null) {
// continue;
// }
// v.setNewPrice(item.getPrice());
// v.setStatus(item.getStatus());
// v.setStock(item.getStock());
// }}... ...
}
- 启动服务并访问接口文档: http://localhost:8081/doc.html#/home
服务调用
需求: 购物车服务需要使用商品服务, 但是代码已经拆分, 所以需要通过网络进行服务调用
Spring给我们提供了一个RestTemplate工具,可以方便的实现Http请求的发送。使用步骤如下:
- 注入RestTemplate到Spring容器
- 发起远程调用
代码改造
- 在启动类创建RestTemplate对象, 并加入到spring容器
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
public class CartApplication {public static void main(String[] args) {SpringApplication.run(CartApplication.class, args);}@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}
- 复制ItemDTO,
- 注入RestTemplate对象, 改造代码
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {//注入RestTemplate对象//1.通过构造函数的形式注入对象//2.用lambda提供的@RequiredArgsConstructor注解自动生成构造函数//3.用final关键字控制对象是否生成构造函数private final RestTemplate restTemplate;private void handleCartItems(List<CartVO> vos) {// 1.获取商品idSet<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查询商品// List<ItemDTO> items = itemService.queryItemByIds(itemIds);//2.1 使用restTemplate远程调用商品服务ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://localhost:8081/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ",")));//2.2解析响应if (!response.getStatusCode().is2xxSuccessful()) {// 查询失败return;}List<ItemDTO> items = response.getBody();... ...}... ...
}
- 接口调式: 商品价格没有变化, 后端就会返回null, 一旦商品价格变化了, 就会查出最新价格, 前端就会展示价差
相关文章:

[Java]微服务拆分
导入项目 本篇及后续的微服务学习都是基于Centos7系统下的Docker部署,因此需要准备: Centos7的环境SSH客户端安装好Docker会使用Docker 之前的学习, 导致虚拟机中存在黑马商城项目以及mysql数据库, 为了保持一致, 需要删除 cd /rootdocker compose down 安装mysq…...
JavaScript逆向爬虫教程-------基础篇之JavaScript混淆原理
目录 一、常量的混淆原理1.1 对象属性的两种访问方式1.2 十六进制字符串1.3 Unicode字符串1.4 字符串的ASCII码混淆1.5 字符串常量加密1.6 数值常量加密二、增加 JS 逆向者的工作量2.1 数组混淆2.2 数组乱序2.3 花指令2.4 jsfuck三、代码执行流程的防护原理3.1 流程平坦化3.2 …...

qt移植到讯为rk3568,包含一些错误总结
qt移植到arm报错动态库找不到 error while loading shared libraries: libAlterManager.so.1: cannot open shared object file: No such file or directory 通过设置环境变量 LD_LIBRARY_PATH就行了。 LD_LIBRARY_PATH是一个用于指定动态链接器在运行时搜索共享库的路径的环…...

使用阿里云快速搭建 DataLight 平台
使用阿里云快速搭建 DataLight 平台 本篇文章由用户 “闫哥大数据” 分享,B 站账号:https://space.bilibili.com/357944741?spm_id_from333.999.0.0 注意:因每个人操作顺序可能略有区别,整个部署流程如果出现出入,以…...
ubuntu设置自启动
1. 把要启动的程序或者脚本(比如A.sh、A1)放在 /usr/sbin 目录中。比如我的 A.sh 只是启动 A1 程序: #!/bin/bash/usr/sbin/A1echo "A1 finish!!!" 需要注意的是,脚本和程序都要有可执行的权限才行 2. 在 /etc/systemd/system 目录中创建 .…...
Paddle分布式训练报NCCL错
应该是没有装NCCL,但是通过NVIDIA官网方式用apt安装报错,说nccl签名有问题 打开官网查找对应版本的nccl:https://developer.nvidia.com/nccl/nccl-legacy-downloads 这里不下载local Ubuntu选项,下载O/S agnostic local install…...

PD3.1快充对我们到底有没有必要?
在科技飞速发展的今天,各种智能设备和电子产品已经渗透到了我们生活的方方面面。随之而来的,是对充电速度和效率的不断追求。正是在这样的背景下,USB联盟于2021年6月发布了最新的快充协议——PD3.1。那么,PD3.1快充协议对我们到底…...

Android OpenGL ES详解——立方体贴图
目录 一、概念 二、如何使用 1、创建立方体贴图 2、生成纹理 3、设置纹理环绕和过滤方式 4、激活和绑定立方体贴图 三、应用举例——天空盒 1、概念 2、加载天空盒 3、显示天空盒 4、优化 四、应用举例——环境映射:反射 五、应用举例——环境映射:折射 六、应用…...

Bugku CTF_Web——字符?正则?
Bugku CTF_Web——字符?正则? 进入靶场 <?php highlight_file(2.php); $keyflag{********************************}; $IM preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match); if…...
C# 中Math.Round 和 SQL Server中decimal(18,2) 不想等的问题
首先了解Math.Round方法的默认舍入规则 在C#中,Math.Round方法使用的是“银行家舍入法”(也叫四舍六入五成双)。这种舍入规则是:当要舍弃的数字小于5时直接舍去;当要舍弃的数字大于5时进位;当要舍弃的数字正…...
lab2:docker基础实战
一、实验目的 1.通过本次实验,完成Docker主机的安装和配置、镜像的搜索和下载、容器生命周期的基本管理、容器网络的管理。 2.通过Dockerfile来构建nginx镜像,了解Dockerfile镜像构建过程。 二、实验内容与实验要求 1.完成Docker的安装和配置。 2.完…...
Druid 1.2 源码导读
Druid 是阿里巴巴开源的数据库连接池和监控组件,广泛用于 Java 应用程序中。Druid 1.2 版本提供了高性能的连接池和丰富的监控功能。以下是对 Druid 1.2 源码的导读,帮助你理解其架构和设计。 1. 源码获取 从 GitHub 上获取 Druid 1.2 的源码ÿ…...
千益畅行,共享旅游卡市场乱象解析与未来展望
在当今旅游市场蓬勃发展的大背景下,共享旅游卡作为一种新兴的旅游消费模式,受到了广泛关注。然而,伴随着其快速发展,市场乱象也层出不穷。作为千益畅行共享旅游卡的全国运营总监,我深感有必要对这些问题进行深入剖析&a…...

Dubbo源码解析-服务导出(四)
一、服务导出 当我们在某个接口的实现类上加上DubboService后,就表示定义了一个Dubbo服务,应用启动时Dubbo只要扫描到了DubboService,就会解析对应的类,得到服务相关的配置信息,比如: 1. 服务的类型&…...
浅谈React的虚拟DOM
React的虚拟DOM:揭秘高效渲染的秘密 在React中,虚拟DOM(Virtual DOM)是一个核心概念,它是React能够提供高效渲染和更新的关键。虚拟DOM是一个轻量级的JavaScript对象,表示真实的DOM树。通过使用虚拟DOM&am…...
linux上海康SDK安装并设置环境变量
将HCNetSDK下linux部分复制到客户端电脑/usr/lib/HCNetSDK下:sudo cp -r H /usr/lib/HCNetSDK H是我的文件夹,要把这个文件夹的内容复制到/usr/lib/HCNetSDK路径里。 编辑:vi ~/.bashrc 找到export,按 i 插入换行添加 export LD_LIBRARY_PATH$LD_LIB…...

【计算机网络】UDP网络程序
一、服务端 1.udpServer.hpp 此文件负责实现一个udp服务器 #pragma once#include <iostream> #include <string> #include <cstdlib> #include <cstring> #include <functional> #include <strings.h> #include <unistd.h> #incl…...

什么是全域电商?有哪些电商代运营公司能做全域电商代运营?
什么是全域电商?有哪些电商代运营公司能做全域电商代运营? 随着电商行业的迅猛发展,传统的单一平台运营模式已经无法满足品牌多元化发展的需求。在此背景下,全域电商作为一种新兴的运营方式应运而生,成为越来越多品牌在…...
微信小程序上传pdf和显示
引用:https://blog.csdn.net/qq_54027065/article/details/129854339 loadResume(){let that thisuni.showLoading({title:"下载中"})wx.downloadFile({url:url,success:(res)>{console.log(res,"res11111")if (res.statusCode 200){setTi…...

MongoDB分布式集群搭建----副本集----PSS/PSA
MongoDB分布式集群 Replication 复制、Replica Set 复制集/副本集 概念 一、 副本集的相关概念 1.概念 “ A replica set is a group of mongod instances that maintain the same data set. ” 一组MongoDB服务器(多个mongod实例)(有不…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...