为何引入Spring-cloud以及远程调用(RestTemplate)

前言:

上一篇文章中介绍了Spring-cloud前奏------集群与分布式的区别,以及微服务与它们的关系,接下来就需要深入理解SpringCloud框架的作用,以及背后相关的知识。

上次提到了Spring-boot,那么此时SpringCloud可以暂时理解为多个SpringBoot服务,服务与服务之间虽然没有直接的关系,但是存在一些调用关系。

因此,一个SpringCloud框架中就存在一些核心组件:

1.服务注册发现: 负责管理微服务实例的地址、状态,让服务之间能动态感知彼此,是微服务通信的基础

2.配置管理:解决微服务集群中配置分散、修改需重启的问题,实现配置集中管理、动态刷新。

3.服务通信:实现服务之间的远程调用,分为 "同步调用" 和 "异步消息" 两类。

4.熔断降级:防止单个服务故障导致雪崩效应,保障系统稳定性。

5.网关:作为微服务的 "门面",负责路由转发、鉴权、限流、日志、跨域等,隔离内外网。

6.链路追踪:追踪微服务调用链路,定位性能瓶颈或故障点。

...

Spring-Cloud背后的原理:

首先以上的组件就是支撑微服务能够顺利启动的前提。

当然SpringCloud一开始的想法是容纳好组件!!!!!!

因此以上的组件大多数其实是其他大佬写的,之后Spring-Cloud发现好用就会将其收入麾下。

因此Spring Cloud有自己的一套规范,包括哪些组件应该收纳进来,那些组件不应该被收纳进来。

现在的Spring-Cloud的规范下有两个门派:

Spring Cloud Netflix
Spring Cloud Alibaba

Spring Cloud Netflix:

该门派是Spring-Cloud早期门派,Spring Cloud Netflix是 Netflix OSS(Netflix Open Source Software)在Spring Cloud规范下的实现.
包含的组件及其主要功能⼤致如下:

Eureka: 服务注册和发现 (官方也使用该组件)
Zuul: 服务⽹关
Ribbon: 负载均衡
Feign: 服务调⽤组件
Hystrix: 断路器, 提供服务熔断和限流
Hystrix Dashboard: 监控⾯板
...
在很⻓的⼀段时间⾥, Spring Cloud ⼀度被泛指 Spring Cloud Netflix. Spring Cloud⼀直以来把
Netflix OSS 套件作为其官⽅默认的⼀站式解决⽅案. 然⽽, Netflix公司在2018年前后宣布其核⼼组
件Hystrix、Ribbon、Zuul等均进⼊维护状态, Spring Cloud 也被迫宣布删除这些维护模块.
因此国内的大佬坐不住了,站出来说要研制自己的Spring-Cloud框架供大家使用。

Spring Cloud Alibaba:

Spring Cloud Alibaba 是阿⾥巴巴集团下的开源组件和云产品在Spring Cloud规范下的实现.
虽然Spring Cloud Alibaba⽬前并不是Spring Cloud官⽅推荐的默认⽅案, 但是Spring Cloud Alibaba
是阿⾥中间件团队主导的⼀个新⽣项⽬,正处于⾼速迭代中. 甚⾄在Alibaba的开源组件还没有织⼊
SpringCloud⽣态之前, 就已经在各⼤公司⼴泛使⽤了

上图是Spring Cloud Alibababa相关的核心组件,非常丰富!!!!

环境搭建:

此时要以SpringCloudAlibaba为例,之后结合使用SpringBoot构建微服务,对相关组件进行学习与使用。

就以电商平台为例,之后将电商服务拆分为两个服务,一个是商品服务,一个是订单服务。只做简单的本地演示,线上演示需要自己学习。

数据准备:

首先使用MySQL构建商品列表,与订单数据表:

sql 复制代码
-- 建库
create database if not exists cloud_order charset utf8mb4;
-- 订单表
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;

-- 产品表
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)

工程搭建:

本次采用JDK17、IDEA作为演示:

首先创建一个Maven项目,目录结构如下:


使⽤properties来进⾏版本号的统⼀管理, 使⽤dependencyManagement来管理依赖, 声明⽗⼯程的打
包⽅式为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>

    <groupId>org.example</groupId>
    <artifactId>spring-cloud-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.6</version>
    </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>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

DependencyManagement 和 Dependencies:

1.dependencies :将所依赖的jar直接加到项⽬中. ⼦项⽬也会继承该依赖.

2.dependencyManagement :只是声明依赖, 并不实现Jar包引⼊. 如果⼦项⽬需要⽤到相关依赖, 需要显式声明. 如果⼦项⽬没有指定具体版本, 会从⽗项⽬中读取version. 如果⼦项⽬中指定了版本号,就会使⽤⼦项⽬中指定的jar版本. 此外⽗⼯程的打包⽅式应该是pom,不是jar, 这⾥需要⼿动 使⽤ packaging 来声明.

版本管理:

Spring Cloud 是基于SpringBoot搭建的, 所以Spring Cloud 版本与SpringBoot版本有关:

创建子项目-订单服务:


声明项⽬依赖 和 项⽬构建插件:

复制代码
<?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">
    <parent>
        <artifactId>spring-cloud-demo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>product-server</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <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>

</project>

实体类:

java 复制代码
import lombok.Data;
import java.util.Date;
@Data
public class OrderInfo {
 private Integer id;
 private Integer userId;
 private Integer productId;
 private Integer num;
 private Integer price;
 private Integer deleteFlag;
 private Date createTime;
 private Date updateTime;
}

Controller:

java 复制代码
@RequestMapping("/order")
@RestController
public class OrderController {
 @Autowired
 private OrderService orderService;
 @RequestMapping("/{orderId}")
 public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId){
 return orderService.selectOrderById(orderId);
 }
}

Service:

java 复制代码
import com.demo.ubs.info.OrderInfo;
import com.demo.ubs.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;
    public OrderInfo selectOrderById(Integer orderId) {
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        return orderInfo;
    }
}

Mapper:

java 复制代码
import com.bite.order.model.OrderInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface OrderMapper {
 @Select("select * from order_detail where id=#{orderId}")
 OrderInfo selectOrderById(Integer orderId);
}

启动服务并进行测试:

创建子项目-商品服务:

声明项⽬依赖 和 项⽬构建插件:

复制代码
<?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">
    <parent>
        <artifactId>spring-cloud-demo</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-server</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <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>
</project>

配置application.yml:

复制代码
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  configuration: # 配置打印 MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true #配置驼峰⾃动转换

商品服务也是如此,同上:
controller:

sql 复制代码
import com.demo.ubs.info.ProductInfo;
import com.demo.ubs.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/product")
public class ProductController {
    @Autowired
    private ProductService productService;
    @RequestMapping("/{productId}")
    public ProductInfo getProductById(@PathVariable("productId") Integer productId){
        System.out.println("收到请求,Id:"+productId);
        return productService.selectProductById(productId);
    }
}

service:

sql 复制代码
import com.demo.ubs.info.ProductInfo;
import com.demo.ubs.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ProductService {
    @Autowired
    private ProductMapper productMapper;
    public ProductInfo selectProductById(Integer id){
        return productMapper.selectProductById(id);
    }
}

实体类:

sql 复制代码
import lombok.Data;
import java.util.Date;
@Data
public class ProductInfo {
    private Integer id;
    private String productName;
    private Integer productPrice;
    private Integer state;
    private Date createTime;
    private Date updateTime;
}

mapper:

sql 复制代码
import com.demo.ubs.info.ProductInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface ProductMapper {
    @Select("select * from product_detail where id=#{id}")
    ProductInfo selectProductById(Integer id);
}

启动并测试:

远程调用:

在学习SpringAlibaba之前,首先思考一个问题,那么服务与服务之间的通信时如何通的呢?当然在大多数情况下还是通过HTTP请求进行通信,因此,此处引入RestTemplate,发送HTTP请求的模板。

代码如下:

java 复制代码
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;
    public OrderInfo selectOrderById(Integer orderId) {
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        String url = "http://127.0.0.1:9090/product/"+orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

RestTemplate 是从 Spring3.0 开始⽀持的⼀个 HTTP 请求工具, 它是⼀个同步的 REST API 客⼾端, 提供了常见的REST请求⽅案的模版
什么是REST?

REST(Representational State Transfer), 表现层资源状态转移.
REST是由HTTP的主要设计者Roy Fielding博⼠在2000年他的博⼠论⽂中提出来的⼀种软件架构⻛格
1.资源: ⽹络上的所有事物都可以抽象为资源, 每个资源都有⼀个唯⼀的资源标识符(URI)
2.表现层: 资源的表现形式, ⽐如⽂本作为资源, 可以⽤txt格式表现, 也可以通过HTML, XML, JSON等格式来表现, 甚⾄以⼆进制的格式表现.
3.状态转移: 访问URI, 也就是客⼾端和服务器的交互过程. 客⼾端⽤到的⼿段,只能是HTTP协议. 这个过程中, 可能会涉及到数据状态的变化. ⽐如对数据的增删改查, 都是状态的转移

相关推荐
毕设源码-邱学长1 小时前
【开题答辩全过程】以 基于JavaWeb的家庭理财管理系统的设计与实现为例,包含答辩的问题和答案
java
plmm烟酒僧1 小时前
TensorRT 推理 YOLO Demo 分享 (Python)
开发语言·python·yolo·tensorrt·runtime·推理
sailing-data1 小时前
【SE】接口标准化
java·开发语言
t***p9351 小时前
idea创建springBoot的五种方式
java
+VX:Fegn08951 小时前
计算机毕业设计|基于springboot+vue的学校课程管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
无名3871 小时前
RTPEngine 官方自带的 perl 测试程序
开发语言·perl·通信
fruge1 小时前
接口 Mock 工具对比:Mock.js、Easy Mock、Apifox 的使用场景与配置
开发语言·javascript·ecmascript
AI小云1 小时前
【数据操作与可视化】Matplotlib绘图-生成其他图表类型
开发语言·python·matplotlib
MediaTea2 小时前
Python 第三方库:plotnine(类 ggplot 的 Python 数据可视化库)
开发语言·python·信息可视化