1.微服务
1.1单体架构
很多创业公司早期或者传统企业会把业务的所有功能实现都打包在⼀个项⽬, 这就是单体架构. 业务的所有功能实现都打包在⼀个war包或者Jar包中, 这种⽅式就称为单体架构

1.2集群和分布式架构
当⽹站的⽤⼾量越来越⼤, 需求也会越来越多, 流量也会越来越⼤,我们从两个⽅⾯进⾏优化:
- 横向: 添加服务器, 把单台机器变成多台机器的集群.
- 纵向: 把⼀个应⽤, 按照业务进⾏拆分, 拆分为多个项⽬. 此架构也称为垂直架构
集群:将⼀个系统完整的部署到多个服务器上, 每个服务器都能提供系统的所有服务, 多个服务器通过负载均衡调度完成任务. 每个服务器称为集群的节点分布式:将⼀个系统拆分为多个⼦系统,多个⼦系统部署在多个服务器上,多个服务器上的⼦系统
协同合作完成⼀个特定任务
1.3集群 vs 分布式
- 从概念上. 集群是多个计算机做同样的事, 分布式是多个计算机做不同的事
- 从功能上. 集群的每⼀个节点功能是相同的, 并且可以替代的. 分布式也是多个节点组成的系统, 但是每个节点完成的业务是不同的, ⼀个节点出现问题, 这个业务就不可访问了
- 从关系上. 分布式和集群在实践中, 很多时候是互相配合使⽤的. ⽐如分布式的某⼀个节点, 可能由⼀个集群来代替. 分布式架构⼤多是建⽴在集群上的. 所以实际的分布式架构设计中并不会把分布式和集群单独区分, ⽽是统称: 分布式架构.
1.4微服务架构
微服务:在分布式架构下, 当部署的服务越来越多, 重复的代码就会越来越多, 服务的调⽤关系也会越来越复杂. 我们可以把⼀些通⽤的, 会被多个上层服务调⽤的共享业务, 提取成独⽴的基础服务, 组成⼀个个微小的服务. 简单来说, 微服务就是很⼩的服务. ⼩到⼀个服务只对应⼀个单⼀的功能, 只做⼀件事. 这个服务可以单独部署运⾏,
2.解决方案-Spring Cloud
2.1基本定义
Spring Cloud 提供了⼀些可以让开发⼈员快速构建分布式服务的⼯具, ⽐如配置管理, 服务发现, 熔断,
智能路由等. 他们可以在任何分布式环境中很好的⼯作.简单来说, Spring Cloud 就是分布式微服务架构的⼀站式解决⽅案, 是微服务架构落地的多种技术的集合.
2.2实现方案
(1)Spring Cloud Netflix
Spring Cloud Netflix是 Netflix OSS(Netflix Open Source Software)在Spring Cloud规范下的实现.
包含的组件及其主要功能⼤致如下:
- Eureka: 服务注册和发现
- Zuul: 服务⽹关
- Ribbon: 负载均衡
- Feign: 服务调⽤组件
- Hystrix: 断路器, 提供服务熔断和限流
- Hystrix Dashboard: 监控⾯板
(2)Spring Cloud Alibaba
Spring Cloud Alibaba 是阿⾥巴巴集团下的开源组件和云产品在Spring Cloud规范下的实现. 如果说Spring Cloud Netflix 是 Spring Cloud 的第⼀代实现, 那么Spring Cloud Alibaba 也可以看做是 Spring Cloud 的第⼆代实现, 主要由 Nacos、Sentinel、Seata 等组件组成
3.环境工程搭建
3.1开发环境安装
JDK:⽬前⻓期维护的版本有: JDK8, JDK11, JDK17, JDK21,在 JDK版本的选择上,尽量选择⻓期维护的版本. Spring Cloud 是基于 SpringBoot 进⾏开发的, SpringBoot 3.X以下的版本, Spring官⽅已不再进⾏维护, SpringBoot 3.X的版本, 使⽤的JDK版本基线为JDK17. 鉴于JDK21 是2023.09⽉发 布的, 很多功能还没有在⽣产环境验证, 所以选择使⽤JDK17来学习
3.2案例引入
实现⼀个电商平台:⼀个电商平台包含的内容⾮常多, 仅从⾸⻚上就可以看到巨多的功能,我们该如何实现呢? 如果把这些功能全部写在⼀个服务⾥, 这个服务将是巨⼤的. 微服务架构是最好的选择. 微服务应⽤开发的第⼀步, 就是服务拆分. 拆分后才能进⾏"各⾃开发"
3.3服务拆分
服务越⼩, 微服务的独⽴性就会越来越⾼, 但同时, 微服务的数量也会越多, 管理这些微服务的难度也会
提⾼. 所以服务拆分也要考虑场景,遵守一定的原则
(1)单⼀职责原则
单⼀职责原则原本是⾯向对象设计中的⼀个基本原则, 它指的是⼀个类应该专注于单⼀功能. 不要存在多于⼀个导致类变更的原因
(2)服务⾃治
服务⾃治是指每个微服务都应该具备⾼度⾃治的能⼒, 即每个服务要能做到独⽴开发, 独⽴测试, 独⽴构建, 独⽴部署, 独⽴运⾏
(3)单向依赖
微服务之间需要做到单向依赖, 严禁循环依赖, 双向依赖
- 循环依赖: A -> B -> C ->A
- 双向依赖: A -> B, B -> A
3.4工程搭建
3.4.1创建父工程
(1)创建⼀个空的Maven项⽬, 删除所有代码, 只保留pom.xml

(2)完善pom文件
使⽤properties来进⾏版本号的统⼀管理, 使⽤dependencyManagement来管理依赖, 声明⽗⼯程的打包⽅式为pom
xml
<?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>
<packaging>pom</packaging>
<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>
</project>
DependencyManagement 和 Dependencies
- dependencies :将所依赖的jar直接加到项⽬中. ⼦项⽬也会继承该依赖.
- dependencyManagement :只是声明依赖, 并不实现Jar包引⼊. 如果⼦项⽬需要⽤到相关依赖, 需要显式声明. 如果⼦项⽬没有指定具体版本, 会从⽗项⽬中读取version. 如果⼦项⽬中指定了版本号,就会使⽤⼦项⽬中指定的jar版本. 此外⽗⼯程的打包⽅式应该是pom,不是jar, 这⾥需要⼿动使⽤ packaging 来声明
3.4.2创建子项目
(1)订单服务
声明项⽬依赖和项⽬构建插件
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>
(2)商品服务
声明和订单服务相同
(3)完善订单服务
完善启动类
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class,args);
}
}
配置文件
java
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false
username: root
password: xxxxx
driver-class-name: com.mysql.cj.jdbc.Driver
#设置MyBatis的xml路径
mybatis:
configuration:
# 配置打印 MyBatis⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 配置驼峰⾃动转换
map-underscore-to-camel-case: true
(4)业务代码
实体类
java
@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;
private ProductInfo productInfo;
}
Mapper层
java
@Mapper
public interface OrderMapper {
@Select("select * from order_detail where id=#{orderId}")
OrderInfo selectOrderById(Integer orderId);
}
Service层
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public OrderInfo selectOrderById(Integer orderId){
OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
return orderInfo;
}
}
Controller层
java
@RequestMapping("/order")
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@RequestMapping("/{orderId}")
//从URL的路径中提取一个名为 "orderId" 的部分,并将其值绑定到方法参数 orderId 上
public OrderInfo getOrderById(@PathVariable("orderId") Integer orderId){
return orderService.selectOrderById(orderId);
}
}
商品服务代码修改参考上述
3.4.3需求分析
(1)需求
根据订单查询订单信息时, 根据订单⾥产品ID, 获取产品的详细信息.
(2)实现方案
- 实现思路: order-service服务向product-service服务发送⼀个http请求, 把得到的返回结果, 和订单结果融合在⼀起, 返回给调⽤⽅.
- 实现⽅式: 采⽤Spring 提供的RestTemplate
(3)定义RestTemplate
java
@Configuration
public class BeanConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
(4)修改Order-Service中的Service
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;
}
}
3.4.4RestTemplate
RestTemplate 是从 Spring3.0 开始⽀持的⼀个 HTTP 请求⼯具, 它是⼀个同步的 REST API 客⼾端, 提供了常⻅的REST请求⽅案的模版;RestTemplate 是Spring提供, 封装HTTP调⽤, 并强制使⽤RESTful⻛格. 它会处理HTTP连接和关闭, 只需要使⽤者提供资源的地址和参数即可.