【微服务】组件、基础工程构建(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,出现如下页面就算调用成功:

相关推荐
蝎子莱莱爱打怪6 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking7 天前
Java微服务练习方式
java·后端·微服务
米丘10 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质13 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
霸道流氓气质13 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
地瓜伯伯13 天前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
Devin~Y13 天前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
递归尽头是星辰13 天前
AI 访问数据仓库:从直连到微服务化
数据仓库·人工智能·微服务·dataagent·ai数据治理
就改了14 天前
Windows 环境 SkyWalking 完整实操教程
windows·微服务·skywalking
至乐活着14 天前
Docker Compose多服务编排实战:从零搭建Node.js+MySQL+Redis全栈应用
docker·微服务·devops·容器编排·compose