【微服务】组件、基础工程构建(day2)

组件

服务注册和发现

微服务模块中,一般是以集群的方式进行部署的,如果我们调用的时候以硬编码的方式,那么当服务出现问题、服务扩缩容等就需要对代码进行修改,这是非常不好的。所以微服务模块中就出现了服务注册和发现组件,比较常用的组件有Eureka、Consul、Nacos,在微服务系列中,也是针对这三个组件来进行介绍。

负载均衡

由于以集群的方式部署,因此我们就要考虑调用哪台机子的问题,所以微服务模块中又出现了负载均衡组件, 在微服务系列中,针对LoadBalancer组件进行介绍。

分布式配置管理

微服务导致会出现大量的服务,而每个服务都需要必要的配置,此时就迫切需要一套集中式的、动态的配置管理设施,在微服务系列中,针对Consul、Nacos组件进行介绍。

网关

微服务的出现导致大量的服务,从而导致大量的IP地址,这对前端是不友好的。但是,本着脏话累活后端来干的优良品质,因此又出现了一系列的组件来解决这个问题,在微服务系列中,针对Gateway组件进行介绍。

服务调用

单体项目中,想要调用别的业务只需要注入即可,但是在微服务中,业务进行拆分,因此无法通过注入的方式来进行调用。不过,例如RestTemplate、HttpClient等都是可以进行URL发送的,但是这种方式也会造成硬编码的出现。于是,微服务又出现了一系列组件来解决这个问题, 在微服务系列中,针对OpenFeign组件进行介绍。

服务链路追踪

微服务应用中,可能一个业务的完成就需要调用N个服务,如果该业务效率低下、响应结果错误。我们就需要去定位是哪里的响应慢、哪里的服务出现错误,但是靠肉眼是没法看出来的。因此,微服务又出现了组件,来对一次调用的链路进行记录,从而可以在出现问题后快速解决问题。 在微服务系列中,针对Micrometer Tracing组件进行介绍。

服务熔断和降级

微服务的出现本来就是为了解决单体项目资源不足的情况,因此当流量过多或者服务出错时,我们就要采取降低流量等措施,对于这种问题, 在微服务系列中,针对Circuit Breaker和Sentinel组件进行介绍。

分布式事务

单体应用中我们经常要用到事务,微服务应用也不例外,因此对于这种应用场景。 在微服务系列中,针对Seata组件进行介绍。

在微服务系列中,基本上就是对上述组件的介绍,不会涉及太多的底层原因,主要是介绍如何进行操作,后续有实力之后再对其源码进行分析介绍。

基础工程构建

业务场景

以订单服务调用商品服务为例,来对SpringCloud的一系列组件进行介绍。

数据准备

-- 建库,商品库
create database if not exists cloud_product charset utf8mb4;
-- 使用库
use cloud_product;
-- 产品表
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail (
`id` BIGINT 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);

-- 建库,订单库
create database if not exists cloud_order charset utf8mb4;
-- 使用库
use cloud_order;
-- 订单表
DROP TABLE IF EXISTS order_detail;
CREATE TABLE order_detail (
 `id` BIGINT 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);

工程搭建

搭建父工程

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wbz</groupId>
    <artifactId>spring-cloud-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>cloud-provider-payment8001</module>
        <module>cloud-consumer-order80</module>
    </modules>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <spring-cloud.version>2023.0.0</spring-cloud.version>
        <spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
        <mysql.version>8.0.31</mysql.version>
        <druid.version>1.2.18</druid.version>
        <mybatis-plus.version>3.5.7</mybatis-plus.version>
        <lombok.version>1.18.28</lombok.version>

    </properties>

    <!--SpringBoot-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencyManagement>

        <dependencies>

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

            <!--SpringCloudAlibaba-->
            <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>

            <!--MySQL驱动-->
            <dependency>
                <groupId>com.mysql</groupId>
                <artifactId>mysql-connector-j</artifactId>
                <version>${mysql.version}</version>
            </dependency>

            <!--Druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <!--MP-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>

            <!--Lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>

        </dependencies>

    </dependencyManagement>

</project>

搭建子工程 - 商品服务

在该业务背景下,商品服务作为服务提供方出现。

搭建一个模块,一般分为:建模块、写pom文件、写yml文件、改主启动类、写业务类。

建模块

写pom文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.wbz</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>cloud-provider-product8001</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!--SpringBoot通用模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--Druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>

        <!--MP-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        </dependency>

    </dependencies>

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

</project>

写yml文件

server:
  port: 8001

spring:
  application:
    name: cloud-provider-payment8001

  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher # 路径匹配策略

  datasource:
      url: jdbc:mysql://127.0.0.1:3306/cloud_product?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

  profiles:
    active: dev

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**Mapper.xml
  type-aliases-package: com.wbz.domain

改主启动类

/**
 * 微服务生产者模块,表示被调用的一方
 */

@MapperScan("com.wbz.mapper")
@SpringBootApplication
public class ProductProviderApplication8001 {

    public static void main(String[] args) {
        SpringApplication.run(ProductProviderApplication8001.class, args);
    }

}

写业务类

// model
/**
 * 产品表
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("product_detail")
public class Product {

    @TableId
    private Long id;

    @TableField
    private String productName;

    @TableField
    private Long productPrice;

    @TableField
    private Integer state;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;

}

// 持久层接口
public interface ProduceMapper extends BaseMapper<Product> {
}

// 服务层接口
public interface ProductService extends IService<Product> {

    Product getProductById(Long productId);

}

// 服务层实现类
@Service
public class ProductServiceImpl extends ServiceImpl<ProduceMapper, Product> implements ProductService {

    @Override
    public Product getProductById(Long productId) {
        return this.getById(productId);
    }

}

// 控制层类
@RestController
@RequestMapping("/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping("/query/{productId}")
    public Product getProductById(@PathVariable Long productId) {
        return this.productService.getProductById(productId);
    }

}

启动项目之后,访问url:127.0.0.1:8001/product/query/1001,返回如下页面就算调用成功:

整体代码结构如下:

搭建子工程 - 订单服务

在该业务背景下,订单服务作为服务调用方出现。

建模块

写pom文件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.wbz</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>cloud-consumer-order80</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!--SpringBoot通用模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--Druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>

        <!--MP-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        </dependency>

    </dependencies>

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

</project>

写yml文件

server:
  port: 80

spring:
  application:
    name: cloud-consumer-order80

  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher # 路径匹配策略

  datasource:
    url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

  profiles:
    active: dev

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**Mapper.xml
  type-aliases-package: com.wbz.domain

改主启动类

/**
 * 微服务消费者模块,调用的一方
 */

@SpringBootApplication
@MapperScan("com.wbz.mapper")
public class OrderConsumerApplication80 {

    public static void main(String[] args) {
        SpringApplication.run(OrderConsumerApplication80.class, args);
    }

}

写业务类

// 实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("order_detail")
public class Order {

    @TableId
    private Long id;

    @TableField
    private Long userId;

    @TableField
    private Long productId;

    @TableField
    private Integer num;

    @TableField
    private Long price;

    @TableField
    private Integer deleteFlag;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;

    @TableField(exist = false)
    private Product product;

}

// mapper接口
public interface OrderMapper extends BaseMapper<Order> {
}

// service接口
public interface OrderService extends IService<Order> {

    Order getOrderById(Integer id);

}

// RestTemplateConfig实现类
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

// service实现类
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Resource
    private RestTemplate restTemplate;

    @Override
    public Order getOrderById(Integer id) {
        Order order = this.getById(id);
        String url = "http://127.0.0.1:8001/product/query/" + order.getProductId();
        Product product = this.restTemplate.getForObject(url, Product.class);
        order.setProduct(product);
        return order;
    }

}

// controller实现类
@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private OrderService orderService;

    @GetMapping("/query/{id}")
    public Order getOrderById(@PathVariable Integer id) {
        return this.orderService.getOrderById(id);
    }

}

启动项目之后,访问url:127.0.0.1/order/query/1,出现如下页面就算调用成功:

相关推荐
掘金-我是哪吒14 小时前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
茶馆大橘15 小时前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
想进大厂的小王18 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
九卷技术录19 小时前
(微服务)服务治理:几种开源限流算法库/应用软件介绍和使用
微服务·服务治理·限流算法
阿伟*rui19 小时前
认识微服务,微服务的拆分,服务治理(nacos注册中心,远程调用)
微服务·架构·firefox
想进大厂的小王1 天前
Spring-cloud 微服务 服务注册_服务发现-Eureka
微服务·eureka·服务发现
Gemini19951 天前
分布式和微服务的区别
分布式·微服务·架构
茶馆大橘1 天前
微服务系列五:避免雪崩问题的限流、隔离、熔断措施
java·jmeter·spring cloud·微服务·云原生·架构·sentinel
coding侠客1 天前
揭秘!微服务架构下,Apollo 配置中心凭啥扮演关键角色?
微服务·云原生·架构
lexusv8ls600h2 天前
微服务设计模式 - 网关路由模式(Gateway Routing Pattern)
spring boot·微服务·设计模式