上一章 能单点启动 order-service;多实例、多服务后客户端不能再记 IP:端口。 服务发现 解决「找谁」;API 网关 解决「从哪进、横切怎么做」。
服务注册发现:服务启动时向注册中心登记自己的 host、port、元数据;消费者从注册中心查询可用实例,而不是写死 URL。ShopFlow 本课选用 Netflix Eureka(Spring Cloud 一等公民);Nacos 在阿里生态与配置中心一体化场景更常见。
| 维度 | Eureka | Nacos |
|---|---|---|
| Spring Cloud 集成 | eureka-server/client 成熟,本课 BOM 直接管理版本 |
spring-cloud-alibaba 另需对齐 BOM |
| 配置中心 | 否(Config Server 另章) | 注册 + 配置一体 |
| 健康模型 | 客户端心跳 + 服务端剔除 | 心跳 + 可选 CP 模式 |
| 本课选择 | ✓ 教程默认,Compose 一键起 | 延伸阅读;生产可评估 |
http://192.168.1.8:8081 写进 Feignspring.application.name 查实例在 脚手架 基础上,为各 service 模块添加 Eureka Client(版本由 Spring Cloud BOM 管理),并新增独立模块 shopflow-discovery-server(或 Docker 镜像)作为注册中心。
@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServerApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryServerApplication.class, args);
}
}
# discovery-server / application-local.yml
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
# order-service / application-local.yml
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
lease-renewal-interval-in-seconds: 10
inventory-service 同理,spring.application.name 必须为 inventory-service(与 Gateway 路由 lb://inventory-service 一致)。
sequenceDiagram
participant O as order-service
participant E as Eureka :8761
participant I as inventory-service
O->>E: REGISTER (8081)
I->>E: REGISTER (8082)
loop 每 10s
O->>E: RENEW 心跳
I->>E: RENEW 心跳
end
Note over E: 超时未续约则剔除实例
注册表是软状态;调用方仍可能遇到 部分失败,需客户端超时与重试。
新增 shopflow-gateway 模块,依赖 spring-cloud-starter-gateway-server-webflux(Spring Cloud 2025 命名;WebFlux 网关为 ShopFlow 默认)。Gateway 从 Eureka 拉取实例,按路由(Route) = 谓词(Predicate)+ 过滤器(Filter)+ 目标 URI 转发流量。
# gateway / application-local.yml(Spring Cloud 2025 属性前缀)
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
server:
webflux:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/api/orders/**
- id: inventory-route
uri: lb://inventory-service
predicates:
- Path=/api/inventory/**
lb:// 表示通过 Spring Cloud LoadBalancer 从 Eureka 选实例。若从旧版迁移,可用 spring-boot-properties-migrator 对照 spring.cloud.gateway.* → spring.cloud.gateway.server.webflux.*。
Path:路径匹配,最常用Header、Method:按头或 HTTP 方法After / Before:时间窗口(金丝雀可扩展)AddRequestHeader:注入 traceId、租户 IDStripPrefix:去掉路径前缀再转发RequestRateLimiter:限流(advanced 章展开)外部客户端只访问 https://api.shopflow.example(本地 :8080),Gateway 负责 TLS 终止(生产)、JWT 校验(安全与部署 章)与把用户身份传给下游。业务服务不应再对外暴露端口。
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: order-api
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- AddRequestHeader=X-ShopFlow-User-Id, #{headers['X-ShopFlow-User-Id']}
# 外部: GET /api/orders/123 → order-service: GET /orders/123
本章仅演示头透传占位;完整 OAuth2 Resource Server 在 Gateway 统一验签后,将 sub 写入 X-ShopFlow-User-Id 即可。勿在 Gateway 写「下单编排」——那是 order-service 职责。
/orders/{id}?对外 API 带 /api 命名空间便于版本与 BFF 区分;对内 微服务 保持领域路径简洁。StripPrefix 去掉第一段 api,避免每个 Controller 重复写前缀。
本地联调推荐 Compose 起 Eureka;业务服务仍可用 IDE / Maven 启动便于断点。Gateway 与 order / inventory 需能访问 8761。
# demos/practice-02-discovery-gateway-lab/docker-compose.yml
services:
discovery-server:
image: eclipse-temurin:21-jre
ports:
- "8761:8761"
# 实际项目: 挂载 discovery-server.jar 或 build 镜像
environment:
SPRING_PROFILES_ACTIVE: docker
docker compose up -d discovery-server(或本地跑 DiscoveryServerApplication)http://localhost:8761,确认 Eureka 控制台可用inventory-service(8082)、order-service(8081),在控制台看到 UP 实例api-gateway(8080),curl http://localhost:8080/api/orders/actuator/health(经路由转发)ORDER-SERVICE、INVENTORY-SERVICE(大写为默认展示)每条对应上一节 h3。
eureka-client + defaultZone;spring.application.name 即服务 ID;心跳续约后注册表才可靠。Path 谓词 + lb://service-id;2025 属性前缀 gateway.server.webflux。过关清单(勾选会保存在本浏览器)
0 / 5 已勾选
下一步:完成 Demo 与测验;继续 OpenFeign、负载均衡与服务间调用,实现 order 同步调用 inventory 预留库存。
按「推荐启动顺序」搭 Eureka + order/inventory + Gateway,完成 8080 转发与实例剔除观察。
register-with-eureka: false 解释为何 Server 不注册自己。ORDER-SERVICE、INVENTORY-SERVICE 为 UP。Path=/api/orders/** → lb://order-service),curl http://localhost:8080/api/orders/actuator/health 经网关可达。StripPrefix=1,说明 /api/orders/... 到下游 /orders/... 的映射。Gateway 先于 Eureka 启动最可能导致长时间 503。请写出正确启动顺序(① Eureka ② inventory ③ order ④ Gateway)。
正确顺序:① → ③ → ② → ④(或 ① → ② → ③ → ④,业务服务顺序可互换,但必须在 Gateway 前)。Gateway 依赖注册表中有可用实例,否则 lb:// 无法解析。
路由写 uri: http://localhost:8081 而非 lb://order-service,且已有 2 实例。会有什么问题?改哪一行?
无法负载均衡与故障转移,扩缩容需改 Gateway 配置。应改路由 uri 为 lb://order-service,由 LoadBalancer 从 Eureka 选实例。
目录:demos/practice-02-discovery-gateway-lab/。验收:Eureka 2 应用 UP + 8080 curl health 成功 + 停 inventory 后观察剔除。