第 221 章:Spring Cloud 入门
学习目标
- 理解 Spring Cloud 全家桶
- 掌握版本选型
- 搭建第一个 Spring Cloud 应用
- 了解核心组件协同
一、Spring Cloud 简介
Spring Cloud 是基于 Spring Boot 的微服务框架,提供分布式系统常用模式。
1.1 核心组件
| 组件 | 替代品 | 作用 |
|---|---|---|
| Spring Cloud Gateway | Zuul, Kong | API 网关 |
| Nacos Discovery | Eureka, Consul | 服务注册与发现 |
| OpenFeign | RestTemplate, WebClient | 声明式 HTTP 客户端 |
| Spring Cloud LoadBalancer | Ribbon | 客户端负载均衡 |
| Spring Cloud Config | Nacos Config, Apollo | 配置中心 |
| Sentinel | Hystrix, Resilience4j | 熔断限流 |
| Spring Cloud Stream | 直接用 MQ | 消息驱动 |
| Spring Cloud Bus | RabbitMQ, Kafka | 配置广播 |
| Spring Cloud Sleuth | Zipkin | 链路追踪 |
1.2 与 Spring Boot 版本对应
| Spring Cloud | Spring Boot |
|---|---|
| 2023.0.x | 3.2.x |
| 2022.0.x | 3.0.x |
| 2021.0.x | 2.7.x |
| Hoxton | 2.3.x |
注意:Spring Boot 3.x 后,JDK 17+。
二、版本生态
2.1 主流选择
推荐:Spring Cloud 2023.x + Nacos + Sentinel + Spring Cloud Gateway
2.2 父 POM
xml
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>2023.0.1</version>
</parent>2.3 Nacos 替代方案
| 特性 | Nacos | Eureka | Consul |
|---|---|---|---|
| 健康检查 | ✅ | ✅ | ✅ |
| 配置中心 | ✅ | ❌ | ✅ |
| 多语言 | ✅ | ❌ | ✅ |
| 一致性协议 | AP/CP | AP | CP |
| 推荐度 | ⭐⭐⭐⭐⭐ | ⚠️ 停维 | ⭐⭐⭐ |
三、快速搭建
3.1 项目结构
ms-demo/
├── order-service/
│ ├── pom.xml
│ └── src/
├── payment-service/
└── inventory-service/3.2 注册中心(Nacos)
启动 Nacos Server:
bash
docker run -d --name nacos \
-p 8848:8848 -p 9848:9848 \
-e MODE=standalone \
nacos/nacos-server:v2.3.0访问: http://localhost:8848/nacos(默认账号 nacos/nacos)
3.3 第一个微服务:订单服务
pom.xml:
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>application.yml:
yaml
server:
port: 8081
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
management:
endpoints:
web:
exposure:
include: health,info,metrics启动类:
java
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}启动后,Nacos 控制台 服务列表 应出现 order-service。
四、服务调用:OpenFeign
4.1 客户端声明
java
@FeignClient("inventory-service")
public interface InventoryClient {
@GetMapping("/api/inventory/{skuId}")
InventoryDTO getStock(@PathVariable String skuId);
@PostMapping("/api/inventory/deduct")
Result<Void> deduct(@RequestBody DeductRequest req);
}4.2 在 Controller 中使用
java
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
private final InventoryClient inventoryClient;
@PostMapping
public Result<OrderDTO> create(@RequestBody OrderRequest req) {
// 远程调用库存服务
InventoryDTO stock = inventoryClient.getStock(req.skuId());
if (stock.getQuantity() < req.quantity()) {
return Result.error(20002, "库存不足");
}
return Result.ok(orderService.create(req));
}
}4.3 Feign 配置
yaml
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 10000
loggerLevel: BASIC
compression:
request:
enabled: true
sentinel:
enabled: true4.4 Feign + Sentinel 熔断
java
@FeignClient(name = "inventory-service", fallback = InventoryFallback.class)
public interface InventoryClient {
@GetMapping("/api/inventory/{skuId}")
InventoryDTO getStock(@PathVariable String skuId);
}
@Component
public class InventoryFallback implements InventoryClient {
@Override
public InventoryDTO getStock(String skuId) {
return InventoryDTO.busy(); // 降级返回
}
}五、网关:Gateway
5.1 第一个网关
pom.xml:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>application.yml:
yaml
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
- id: inventory-service
uri: lb://inventory-service
predicates:
- Path=/api/inventory/**5.2 自定义过滤器
java
@Component
public class AuthGatewayFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst("Authorization");
if (token == null) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}六、配置中心
6.1 Nacos Config 集成
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>bootstrap.yml(注意不是 application.yml):
yaml
spring:
application:
name: order-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
refresh-enabled: true6.2 Nacos 中创建配置
DataId: order-service.yaml
yaml
order:
timeout: 5000
maxRetry: 3
server:
port: 80816.3 动态刷新
java
@RefreshScope
@RestController
public class ConfigController {
@Value("${order.timeout}")
private int timeout;
@GetMapping("/config")
public String config() {
return "timeout=" + timeout;
}
}七、链路追踪
7.1 集成 Sleuth + Zipkin
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>yaml
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0启动 Zipkin:
bash
docker run -d -p 9411:9411 openzipkin/zipkin访问: http://localhost:9411
八、消息驱动:Stream
8.1 简化 MQ 使用
java
public interface OrderEventChannel {
String INPUT = "order-events-in";
String OUTPUT = "order-events-out";
@Output(OUTPUT)
MessageChannel out();
@Input(INPUT)
SubscribableChannel in();
}java
@Service
@RequiredArgsConstructor
public class OrderEventPublisher {
private final OrderEventChannel channel;
public void publish(OrderEvent event) {
channel.out().send(MessageBuilder.withPayload(event).build());
}
}java
@Component
public class OrderEventSubscriber {
@StreamListener(OrderEventChannel.INPUT)
public void handle(OrderEvent event) {
log.info("收到事件: {}", event);
}
}九、Spring Cloud 生态完整图
十、演进路线
十一、常见错误
| 错误 | 解决 |
|---|---|
UnknownHostException | 注册中心未启动 / 网络不通 |
Load balancer does not have available server | 未启用 lb:// 或未引入负载均衡 |
| Feign 404 | 注意 @PathVariable 注解 |
| 配置不生效 | bootstrap.yml 优先于 application.yml |
| 熔断器不生效 | 没加 @SentinelResource 或 @EnableCircuitBreaker |
十二、本章小结
| 组件 | 作用 | 学习章节 |
|---|---|---|
| Nacos | 注册 + 配置 | 222 |
| OpenFeign | 服务调用 | 223 |
| Gateway | API 网关 | 224 |
| Config | 配置中心 | 225 |
| Sentinel | 熔断限流 | 微服务治理章 |
| Sleuth | 链路追踪 | 见 73 章 |
动手练习
- 用 Spring Boot 3.2 + Spring Cloud 2023 创建 2 个服务,接入 Nacos
- 用 OpenFeign 实现服务间调用
- 搭建 Spring Cloud Gateway,做路由转发
- 用 Nacos Config 做动态配置