[Java]微服务拆分

导入项目

本篇及后续的微服务学习都是基于Centos7系统下的Docker部署,因此需要准备:

  • Centos7的环境
  • SSH客户端
  • 安装好Docker
  • 会使用Docker

之前的学习, 导致虚拟机中存在黑马商城项目以及mysql数据库, 为了保持一致, 需要删除

  • cd /root
  • docker compose down

安装mysql

  1. 在课前资料提供好了MySQL的一个目录, 其中有MySQL的配置文件和初始化脚本:

  1. 我们将其复制到虚拟机的 /root 目录。如果 /root下已经存在 mysql 日录则删除旧的

  1. 新建一个通用网络

  1. 安装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

  1. 远程连接mysql

  • 账密: root/123

运行后端

  1. 在课前资料提供了一个hmall目录, 将其复制到你的工作空间,然后利用Idea打开

  1. 修改application-local.yaml文件, 配置自己的数据库IP地址

  1. 按下 ALT +8键打开services窗口,新增一个启动项, 在弹出窗口中鼠标向下滚动,找到 Spring Boot

  • 目的就是让程序运行时读取local环境的配置文件
  • 作用等同于修改下面的配置, 修改代码的话, 部署时要改回来, 麻烦

  • 要把Mybatis的版本改为3.4.2, 不然上面的步骤会出现问题
  1. 启动服务并访问

运行前端

  1. 在课前资料中还提供了一个hmall-nginx的目录

  1. 其中就是一个nginx程序以及前端代码,将其复制到一个非中文、不包含特殊字符的目录下。
  2. 然后进入hmall-nginx目录,利用cmd启动即可, 双击exe启动关闭时不方便

  1. 访问前端

  • http://localhost:18080/
  • jack/123

认识微服务

单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署

优点:: 架构简单, 部署成本低

缺点: 团队协作成本高, 系统发布效率低, 系统可用性差

总结: 单体架构适合开发功能相对简单,规模较小的项目

comcat服务器的连接数是有限的, 随着并发请求量的上升, 整个系统的响应速度就会变慢

微服务架构,是服务化思想指导下的一套最佳实践架构方案。服务化,就是把单体架构中的功能模块拆分为多个独立项目

优势: 粒度小, 团队自治, 服务自治

劣势: 部署和运维的复杂度提高, 跨模块的任务难度提高

SpringCloud是目前国内使用最广泛的微服务框架。集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验

官网地址: https://spring.io/proiects/spring-cloudSpringCloud

SpringCloud基于SpringBoot实现了微服务组件的自动装配,从而提供了良好的开箱即用体验。但对于SpringBoot的版本也有要求:

服务拆分

熟悉黑马商城

核心业务包含用户模块, 购物车模块, 支付模块

服务拆分原则

什么时候拆分?

创业型项目: 先采用单体架构,快速开发,快速试错。随着规模扩大,逐渐拆分。

确定的大型项目: 资金充足,目标明确,可以直接选择微服务架构,避免后续拆分的麻烦。

怎么拆分?

  1. 从拆分目标来说,要做到:

高内聚: 每个微服务的职责要尽量单一,包含的业务相互关联度高、完整度高。

低耦合: 每个微服务的功能要相对独立,尽量减少对其它微服务的依赖。

  1. 从拆分方式来说,一般包含两种方式:

纵向拆分: 按照业务模块来拆分

横向拆分: 抽取公共服务,提高复用性

拆成什么样?

微服务的工程结构有两种: 独立Project 和 Maven聚合

  • 独立Project结构的微服务工程适合超大工程, 各个服务绝对独立, 但是代码分散, 管理成本较高
  • Maven聚合适合一般工程, 父工程下, 各个服务被划分为模块, 项目还是集中管理

拆分服务

拆分商品服务item-service

将hm-service中与商品管理相关功能拆分到一个微服务module中,命名为item-service

  • 飞书文档: Docs

  1. 新建模块

  1. 拷贝依赖: 从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>

  1. 创建启动类: 拷贝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);
    }
}

  1. 准备数据库: 真实项目中一般是独立服务独立mysql, 我们采用一个mysql独立database, 进行数据隔离

  • 使用资料中提供的sql文件, 创建数据表并插入数据
  • 注意要启动linux中的mysql服务

  1. 准备配置文件: 拷贝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/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: ${hm.db.pw}
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  global-config:
    db-config:
      update-strategy: not_null
      id-type: auto
logging: #日志配置
  level: #日志记录级别
    com.hmall: debug
  pattern: #日志日期格式
    dateformat: HH:mm:ss:SSS
  file:  #日志保存目录
    path: "logs/${spring.application.name}"
knife4j: #swagger配置
  enable: true
  openapi:
    title: 黑马商城商品管理接口文档
    description: "黑马商城商品管理接口文档"
    email: 123456@qq.com
    concat: 王
    url: https://www.itcast.cn
    version: v1.0.0
    group:
      default:
        group-name: default
        api-rule: package
        api-rule-resources: # 指定扫描的包
          - com.hmall.item.controller
hm:
  db:
    host: 192.168.1.97 # 修改为你自己的虚拟机IP地址
    pw: 123 # 修改为docker中的MySQL密码

  1. 拷贝业务代码

  1. 先复制实体类, 再复制mapper, 再复制service, 再复制controller
  2. 代码报错都是因为导包的路径发生了变化, 删除后让idea重新导入
  3. ItemServiceImpl中要手动修改下包的路径

  1. 补充
  • po是用来封装数据库数据的
  • vo是返回给前端的
  • dto是封装前端请求参数的

  1. 启动服务: 通过spring boot启动项启动服务, 快捷键 alt + 8

如果启动类没有出现在启动项面板, ,

  • 可以刷新maven重试

  • 或者手动添加

  1. 访问接口文档 http://localhost:8081/doc.html#/home

拆分购物车服务cart-service

将hm-service中与购物车有关的功能拆分到一个微服务module中,命名为cart-service

  1. 新建模块

  1. 拷贝依赖: 从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>

  1. 创建启动类: 拷贝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);
    }
}

  1. 准备数据库: 使用资料中提供的sql文件, 创建数据表并插入数据

  1. 准备配置文件: 拷贝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/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: ${hm.db.pw}
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
  global-config:
    db-config:
      update-strategy: not_null
      id-type: auto
logging: #日志配置
  level: #日志记录级别
    com.hmall: debug
  pattern: #日志日期格式
    dateformat: HH:mm:ss:SSS
  file:  #日志保存目录
    path: "logs/${spring.application.name}"
knife4j: #swagger配置
  enable: true
  openapi:
    title: 黑马商城购物车管理接口文档
    description: "黑马商城购物车管理接口文档"
    email: 123456@qq.com
    concat: 王
    url: https://www.itcast.cn
    version: v1.0.0
    group:
      default:
        group-name: default
        api-rule: package
        api-rule-resources: # 指定扫描的包
          - com.hmall.cart.controller

  1. 拷贝业务代码

  1. 先复制实体类, 再复制mapper, 再复制service, 再复制controller
  2. 代码报错都是因为导包的路径发生了变化, 删除后让idea重新导入
  3. CartServiceImpl中耦合了其他模块的功能, 暂时注释掉
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

    // 拆分微服务后, 无法注入其他模块的service使用了
    // private final IItemService itemService;
    ... ...

    @Override
    public 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());
//        }
    }
  ... ...
}

  1. 启动服务并访问接口文档: http://localhost:8081/doc.html#/home

服务调用

需求: 购物车服务需要使用商品服务, 但是代码已经拆分, 所以需要通过网络进行服务调用

Spring给我们提供了一个RestTemplate工具,可以方便的实现Http请求的发送。使用步骤如下:

  1. 注入RestTemplate到Spring容器

  1. 发起远程调用

代码改造

  1. 在启动类创建RestTemplate对象, 并加入到spring容器
@MapperScan("com.hmall.cart.mapper")
@SpringBootApplication
public class CartApplication {
    public static void main(String[] args) {
        SpringApplication.run(CartApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
  1. 复制ItemDTO,

  1. 注入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.获取商品id
        Set<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();
        
        ... ...
    }

    ... ...
}
  1. 接口调式: 商品价格没有变化, 后端就会返回null, 一旦商品价格变化了, 就会查出最新价格, 前端就会展示价差

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】内存池

目录 一、什么是内存池 1.池化技术 2.内存池 3.内存池主要解决的问题 二、内存池的实现 1.New申请空间 2.Delete释放空间 3.再看New申请空间 4.内存池完整代码 三、内存池性能测试 一、什么是内存池 1.池化技术 所谓 "池化技术"&#xff0c;就是程序向系统…

计算机新手练级攻略——如何搜索问题

目录 计算机学生新手练级攻略——如何搜索问题1.明确搜索意图2.使用精确关键词3.使用专业引擎搜索4.利用好技术社区1. Stack Overflow2. GitHub3. IEEE Xplore4. DBLP 5.使用代码搜索工具1. GitHub 代码搜索2. Stack Overflow 代码搜索3. Papers with Code4. IEEE Xplore 6.查阅…

区块链技术在电子政务中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 区块链技术在电子政务中的应用 区块链技术在电子政务中的应用 区块链技术在电子政务中的应用 引言 区块链技术概述 定义与原理 发…

stm32 踩坑笔记

串口问题&#xff1a; 问题&#xff1a;会改变接收缓冲的下一个字节 串口的初始化如下&#xff0c;位长度选择了9位。因为要奇偶校验&#xff0c;要选择9位。但是接收有用数据只用到1个字节。 问题原因&#xff1a; 所以串口接收时会把下一个数据更改

034集——JIG效果实现(橡皮筋效果)(CAD—C#二次开发入门)

可实现效果如下&#xff08;对象捕捉F3需打开&#xff0c;否则效果不好&#xff09;&#xff1a; public class CircleJig : EntityJig{public static void DraCJig(){PromptPointResult ppr Z.ed.GetPoint("a");if (ppr.Value null) return;Point3d pt ppr.Value…

数据资产入表,如何接住这“泼天的富贵”?

很多管理者没有意识到&#xff0c;数据资产入表是企业增加资产的一场“开卷考试”。 “数据资产入表”&#xff0c;指在企业的资产负债表上体现数据资产&#xff0c;在法律上认可数据资产的财务价值。去年财政部发布《企业数据资源相关会计处理暂行规定》&#xff0c;并于今年…

更稳更高效!大道云行助力广电业务腾飞!

重庆广播电视集团成立于2004年11月&#xff0c;旗下拥有5套广播频率、13套电视频道、覆盖全市3300万人口的有线、无线传输网络&#xff0c;以及由第1眼新闻、视界网、官方微信微博群等组成的新媒体矩阵&#xff0c;融合传播综合实力位居全国前列。 目前&#xff0c;重庆广电全…

NIST密码学未来展望:Naughty Step 上的 SHA-1、3DES 和 SHA-224

1. 引言 NIST 几十年来一直致力于推动密码学标准的发展&#xff0c;2024年10月&#xff0c;其发布了Transitioning the Use of Cryptographic Algorithms and Key Lengths 草案&#xff1a; 概述了 SHA-1&#xff08;为160位哈希算法&#xff09; 将在不久的将来退役&#xf…

物理验证Calibre LVS | SMIC Process过LVS时VNW和VPW要如何做处理?

SMIC家工艺的数字后端实现PR chipfinish写出来的带PG netlist如下图所示。我们可以看到标准单元没有VNW和VPW pin的逻辑连接关系。 前几天小编在社区星球上分享了T12nm ananke_core CPU低功耗设计项目的Calibre LVS案例&#xff0c;就是关于标准单元VPP和VBB的连接问题。 目前…

今天给在家介绍一篇基于jsp的旅游网站设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

【C#设计模式(4)——构建者模式(Builder Pattern)】

前言 C#设计模式(4)——构建者模式(Builder Pattern) 运行结果 代码 public class Computer {private string part1 "CPU";private string part2 "主板";private string part3 "内存";private string part4 "显卡";private st…

软件测试第二篇软件测试技术

第五章单元测试和集成测试的技术 单元静态测试主要由开发人员完成。 标准&#xff1a;规定什么能做&#xff0c;什么不能做。 规范&#xff1a;建议你要怎么做。 5.1.2 代码评审 代码评审是一种发现代码缺陷的另一种测试方法。 代码审查的最佳实践&#xff1a; 创建代码审…

【Android、IOS、Flutter、鸿蒙、ReactNative 】文本点击事件

Android Studio 版本 Android Java TextView 实现 点击事件 参考 import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast;public c…

二叉树(C 语言)

目录 一、树1. 树的概念2. 树的表示方法3. 树在实际当中的应用 二、二叉树1. 二叉树的定义2. 现实中的二叉树3. 特殊的二叉树4. 二叉树的性质5. 二叉树的存储结构 三、堆 —— 完全二叉树的顺序存储1. 堆的概念2. 堆的性质3. 堆的设计思路4. 堆的实现代码 四、堆排序1. 堆排序的…

游戏引擎学习第五天

这节貌似没讲什么 视频参考:https://www.bilibili.com/video/BV1Gmm2Y5EwE/ uint8 *A somewhere in memory; uint8 *B somewhere in memory;//BEFORE WE GOT TO HERE int Y *B; // whatever was actually there before the 5 *A 5; int X *B; // 5 //Obviously! Y and …

大路灯护眼灯十大品牌哪个牌子好?儿童大路灯护眼灯品牌排行榜

大路灯护眼灯十大品牌哪个牌子好&#xff1f;长时间在不良光线下用眼很容易引起视觉疲劳&#xff0c;最终影响视力健康&#xff0c;这个时候大路灯护眼灯以良好的性能成为了很不错的照明产品。不过如今行业热度很高&#xff0c;网红跨界品牌大路灯护眼灯出于成本压缩&#xff0…

1.2 图像处理基本操作

在本实战中&#xff0c;我们将学习如何使用OpenCV进行基本的图像处理操作。首先&#xff0c;我们将通过cv2.imread()函数读取图像&#xff0c;并使用cv2.imshow()在窗口中显示它。接着&#xff0c;我们将探索如何通过cv2.imwrite()保存图像&#xff0c;并设置不同的参数以控制图…

K8S如何基于Istio实现全链路HTTPS

K8S如何基于Istio实现全链路HTTPS Istio 简介Istio 是什么?为什么选择 Istio?Istio 的核心概念Service Mesh(服务网格)Data Plane(数据平面)Sidecar Mode(边车模式)Ambient Mode(环境模式)Control Plane(控制平面)Istio 的架构与组件Envoy ProxyIstiod其他组件Istio 的流量管…

手动搭建 Ghost 博客

操作场景 Ghost 是使用 Node.js 语言编写的开源博客平台&#xff0c;您可使用 Ghost 快速搭建博客&#xff0c;简化在线出版过程。本文档介绍如何在腾讯云云服务器&#xff08;CVM&#xff09;上手动搭建 Ghost 个人网站。 进行 Ghost 网站搭建&#xff0c;您需要熟悉 Linux …

MySQL之索引(3)(索引基本语法、SQL执行计划、常见索引失效原因与解决方法)

目录 一、索引基本语法。 &#xff08;1&#xff09;创建索引。 &#xff08;2&#xff09;查看索引。 &#xff08;3&#xff09;删除索引。 &#xff08;4&#xff09;给多列添加组合索引。 1、何时添加索引&#xff1f;&#xff1f; 2、组合索引。 二、SQL执行计划。 &#…