SpringCloud:通过订单服务认识什么是微服务

在初学java时,如果我们写一个订单+商品服务系统,一般会把这两个服务放在同一个项目中,共用一个pom文件和同样的配置信息,两个实例对应的数据表也会放在同一个数据库中。

微服务的由来

随着业务规模增长,单体项目的弊端逐渐暴露:

当流量访问过大时,我们的服务器会因为流量过大而崩溃,造成巨大的损失;

项目功能实现随着生产越来越多,服务器所承载的功能也越来越大,服务和服务之间的耦合性变高,当我们需要改动一处代码时,可能需要改动多处代码,对我们程序员来说其实是很不方便的

如何解决这个问题?

为了解决这个问题,技术大佬们提出了微服务的概念。

微服务的概念

"微"就是把一个庞大的项目拆分成一个个微小的项目 ,一个微服务只负责单一业务模块,实现服务间解耦,提升独立性和可维护性。

很明显,微服务就是把一个大项目拆分成多个微小且独立的项目,部署在不同的服务器上。

服务拆分原则

误区:服务拆分不是越小越好,也不是越细越好,服务越小,微服务架构的优点和缺点就会越来越明显。

服务越小,微服务的独立性越高,同时管理微服务的成本也会增加,所以微服务的拆分要根据场景来判断。

  • 单一职责原则
    一个服务应该遵循实现一个功能,如果多于一个容易导致类变更问题。
  • 服务自洽
    一个单独的服务项目应该能够独立进行开发,构建,自主管理,打包,部署······
  • 单项依赖
    不能存在循环依赖,如:A->B->A 或者 A->B->C->A

以订单系统为例将项目拆分成两个子项目:

商场服务服务可以拆分成两个服务:订单服务+产品服务。

订单服务:通过订单id查询订单信息

产品服务:通过产品id查询产品信息

服务之间通过远程调用通信(后面Nacos+OpenFeign实现):订单服务通过产品id获得产品信息

服务实现流程图:在这里插入图片描述

如何通过代码实现微服务:

准备工作:

1.创建两个数据库分别存放订单数据表和产品数据表(微服务推荐数据库分离,这是最佳实践;单体项目所有表放同一个库)

sql 复制代码
-- 订单服务

-- 建库
create database if not exists cloud_order charset utf8mb4;

use cloud_order;
-- 订单表
DROP TABLE IF EXISTS order_detail;
CREATE TABLE order_detail (
        `id` INT NOT NULL AUTO_INCREMENT COMMENT '订单id',
        `user_id` BIGINT ( 20 ) NOT NULL COMMENT '用户ID',
        `product_id` BIGINT ( 20 ) NULL COMMENT '产品id',
        `num` INT ( 10 ) NULL DEFAULT 0 COMMENT '下单数量',
        `price` BIGINT ( 20 ) NOT NULL COMMENT '实付款',
        `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id )) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '订单表';

-- 数据初始化
insert into order_detail (user_id,product_id,num,price)
values
(2001, 1001,1,99), (2002, 1002,1,30), (2001, 1003,1,40),
(2003, 1004,3,58), (2004, 1005,7,85), (2005, 1006,7,94);

-- 产品服务
create database if not exists cloud_product charset utf8mb4;

-- 产品表
use cloud_product;
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail (
        `id` INT NOT NULL AUTO_INCREMENT COMMENT '产品id',
        `product_name` varchar ( 128 ) NULL COMMENT '产品名称',
        `product_price` BIGINT ( 20 ) NOT NULL COMMENT '产品价格',
        `state` TINYINT ( 4 ) NULL DEFAULT 0 COMMENT '产品状态 0-有效 1-下架',
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id )) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '产品表';

-- 数据初始化
insert into product_detail (id, product_name,product_price,state)
values
(1001,"T恤", 101, 0), (1002, "短袖",30, 0), (1003, "短裤",44, 0), 
(1004, "卫衣",58, 0), (1005, "马甲",98, 0),(1006,"羽绒服", 101, 0), 
(1007, "冲锋衣",30, 0), (1008, "袜子",44, 0), (1009, "鞋子",58, 0),
(10010, "毛衣",98, 0);

2.创建java项目,作为父项目

父项目本身不写业务代码,作为Maven聚合工程,统一管理所有子模块的依赖版本。

3.在父项目中创建子模块

微服务在开发阶段,可以在父项目下创建多个子模块;运行部署阶段,各个子模块打包后就是互相独立的服务,可以部署在不同服务器。

4.在父项目中管理依赖版本号

dependencyMangament 和dependency的区别

  • dependencyMangament只是声明依赖,不实现jar包引入,如果子项目需要用到相关依赖,需要显示声明,就会使用子项目中指定的jar版本,同时父工程的打包方式应该是pom,不是jar,这里需要手动使用packaging来声明。
  • 使用dependency标签会将该依赖从jar包中引入到项目中,并被子项目继承

删除原来的properties标签,从开始复制,到,声明不复制

xml 复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <java.version>17</java.version>
        <mybatis.version>3.0.3</mybatis.version>
        <mysql.version>8.0.33</mysql.version>
        <spring-cloud.version>2022.0.3</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <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>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter-test</artifactId>
                <version>${mybatis.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

springcloud,mybatis,mysql,mybatistest和Springboot 的版本要相对应,详细资料参考官网:https://spring.io/projects/spring-cloud

5.配置子项目依赖

子项目中的依赖互不干扰,独立添加管理

xml 复制代码
 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

添加lombok依赖

xml 复制代码
 <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

配置子项目

  • 子项目端口号不能一致,必须单独配置
  • 子项目连接的数据库也不一致,需要单独配置

6.创建盒数据表对应的实体类(类中的属性需和表中的字段一一对应)

orderInfo

java 复制代码
@Data
public class orderInfo {
    private Integer id;
    private String userId;
    private Integer productId;
    private Integer num;
    private Integer price;
    private Integer deleteFlag;
@JsonFormat(pattern = "yyyy-MM-dd")
    private Date createTime;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date updateTime;
    private productInfo productInfo;

}

productInfo

java 复制代码
@Data
public class productInfo {
    private Integer id;
    private String productName;
    private Integer productPrice;
    private Integer state;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createTime;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date updateTime;
}

业务代码实现:

如何实现远程调用?

使用RestTemplate

Spring3.0开始支持的一个HTTP请求工具,它是一个同步的RESTAPI客户端,提供了常见的REST请求方法的模版。强制使用RSTful风格,处理HTTP连接和关闭,只需要使用者提供资源的地址和参数即可

缺点:

1.接口对外开放,比较危险

2.url固定写死,修改url时较复杂

3.多机部署无法处理

踩坑总结:

1.父项目的pom文件必须设置为pom,不然父项目无法管理依赖。

2.父项目只是作为一个容器统一管理子项目依赖的版本号,没有业务代码实现,也没有启动类

3.远程调用是通过服务端的应用名进行访问,所以在远程调用的代码中,服务端的名称一定要合服务端设置的application.name相匹配

4.在实际,不会把两个项目放在同一个父项目中,因为实际上一个业务是由一个团队负责,这里只是介绍如何创建父子项目

相关推荐
小番茄程序猿1 小时前
RAG 的 precision 只有 0.55,我以为检索烂了,MRR 一测才发现是我用错了尺子
java·后端
llqbzllll1 小时前
MySQL 索引为什么会失效?用同一张表前后 EXPLAIN 定位原因
后端
天空鸟_时光不老1 小时前
07-检查点与状态持久化
java·人工智能·spring boot·spring·spring cloud·kafka·maven
程序猿_极客1 小时前
【免费】2026分享一套优质的基于Java的电子产品抢购管理系统的设计与实现(智能推荐算法+可视化图表),源码+文档+视频详解(讲解)
java·spring boot·后端·协同过滤·电子产品抢购系统
天空鸟_时光不老1 小时前
09-RAG问答系统落地:从默认分割器的坑到Milvus召回调优
java·人工智能·spring boot·spring·spring cloud·maven·mybatis
小羊没烦恼!2 小时前
Windows Azure Platform体验(1):Windows Azure
java·大数据·后端·python·flask·word·.net
小小张说故事2 小时前
Python 装饰器到底是个啥?从 @ 符号到手写一个,5 个例子讲透
后端·python
CodeSheep2 小时前
朋友面试谈薪报价2w,HR非得压到1.9,还反问他:你就差这1000块钱?后来背调时问了他前同事十几个问题,对方最后直接挂了
前端·后端·程序员
fundoit2 小时前
资源服务器如何对 JWT 进行验签
java·运维·服务器·spring boot·php·oauth2