Spring Cloud 微服务:服务发现、配置与网关
Spring Cloud 微服务入门:服务发现、配置与网关
本教程面向微服务初学者,从零开始讲解 Spring Cloud 生态中最核心的三大基础设施:服务发现(Eureka)、分布式配置(Spring Cloud Config)和 API 网关(Spring Cloud Gateway)。你将通过可运行的代码示例快速掌握它们的配置与集成方式,为构建弹性、可维护的微服务体系打下坚实基础。
环境准备
- JDK 17+
- Maven 3.8+
- Spring Boot 3.x + Spring Cloud 2022.0.x(与 Boot 3 兼容)
- IDE(推荐 IntelliJ IDEA)
- Git(供 Config Server 使用本地仓库测试时可选)
版本对齐:本教程使用 Spring Cloud 2022.0.4 (即
2022.0.x版本),对应 Spring Boot 3.1.x。若使用 Spring Boot 2.x,建议使用 Spring Cloud Hoxton.SR12 或 2021.0.x 系列。
1. 服务发现:Eureka
1.1 什么是服务发现
在微服务架构中,服务实例的网络位置(IP 和端口)是动态变化的。服务发现机制允许服务之间通过逻辑名称而非硬编码地址进行通信。Eureka 是 Netflix 实现的服务注册与发现组件,包含两个角色:
- Eureka Server:注册中心,维护所有服务实例的清单。
- Eureka Client:服务提供方启动时向 Server 注册自己;服务消费方从 Server 获取服务列表,实现客户端负载均衡。
1.2 搭建 Eureka Server
新建 Spring Boot 项目,添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
主启动类添加 @EnableEurekaServer:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
application.yml 配置:
server:
port: 8761
eureka:
client:
register-with-eureka: false # 禁止Server注册自己
fetch-registry: false
server:
enable-self-preservation: false # 开发环境关闭自我保护,方便测试
启动后访问 http://localhost:8761 看到 Eureka 控制台。
1.3 注册服务提供者
创建一个服务提供者(如用户服务),添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
启动类无需特殊注解(Spring Cloud 自动通过依赖检测注册),或者添加 @EnableDiscoveryClient 以示明确。
提供接口:
@RestController
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable String id) {
return "User info for id: " + id + " from port:" + serverPort;
}
@Value("${server.port}")
private String serverPort;
}
配置文件:
spring:
application:
name: user-service # 服务名,极为重要
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
启动后,Eureka 控制台会显示 USER-SERVICE 实例。你可以复制该服务,用不同端口(8082、8083)启动多个实例,观察注册中心的效果。
1.4 服务消费者与负载均衡
消费者同样是一个 Eureka Client,并集成 Spring Cloud LoadBalancer(Spring Cloud 2020 后推荐代替 Ribbon):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
使用 RestTemplate 加 @LoadBalanced 实现负载均衡:
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/user/{id}")
public String consumeUser(@PathVariable String id) {
// 使用服务名代替 IP:Port
String url = "http://user-service/user/" + id;
return restTemplate.getForObject(url, String.class);
}
}
启动消费者,多次访问 /consumer/user/1,会轮询到不同的 user-service 实例,证明负载均衡生效。
1.5 高可用与健康检查
- 健康检查:默认 Eureka 通过心跳判断服务状态,服务端可配置
eureka.instance.lease-renewal-interval-in-seconds控制心跳间隔。 - 自我保护:生产环境应开启
eureka.server.enable-self-preservation=true,防止网络分区时误剔除健康实例。 - 高可用:至少部署两个 Eureka Server 并互相注册,Client 配置多个
defaultZone地址逗号分隔。
2. 分布式配置:Spring Cloud Config
2.1 为什么需要配置中心
微服务数量众多,分散管理配置耗时且易出错。配置中心将配置集中存储(Git、SVN、本地文件),服务启动时主动拉取,并支持运行时动态刷新。
Spring Cloud Config 分为:
- Config Server:连接配置仓库,对外提供配置接口。
- Config Client:从 Server 获取自身配置。
2.2 Config Server 搭建
新建项目,添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
启动类加 @EnableConfigServer:
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
配置 application.yml:
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-repo/config-repo # Git 仓库地址
search-paths: '{application}'
default-label: main
# 若使用本地文件测试,可替换为:
# profiles:
# active: native
# cloud:
# config:
# server:
# native:
# search-locations: classpath:/config
在 Git 仓库中创建 user-service.yml(或 user-service-dev.yml):
server:
port: 8081
my:
custom: Hello from Config Server
验证:访问 http://localhost:8888/user-service/default 或 http://localhost:8888/user-service/dev,应返回配置内容。
2.3 Config Client 接入
在 user-service 中增加 Config Client 依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 动态刷新需要 actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
bootstrap.yml(优先于 application.yml 加载):
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888
profile: dev # 激活 profile
label: main
将配置从 application.yml 迁移到 Git 仓库,本地只保留必需项(如 config 定位信息)。启动服务,会自动从 Config Server 拉取配置。
2.4 配置刷新与动态更新
当 Git 中配置变更时,客户端不需要重启即可刷新。在 Controller 上添加 @RefreshScope:
@RefreshScope
@RestController
public class ConfigTestController {
@Value("${my.custom}")
private String customValue;
@GetMapping("/custom")
public String getCustom() {
return customValue;
}
}
修改 Git 仓库中的 my.custom 值并 commit,然后调用客户端刷新端点:
curl -X POST http://localhost:8081/actuator/refresh
再次访问 /custom 将返回新值。注意,生产环境通常结合 Spring Cloud Bus 广播刷新事件。
3. API 网关:Spring Cloud Gateway
3.1 网关的作用
网关作为系统统一入口,提供路由转发、协议转换、安全认证、流量控制、日志监控等功能。Spring Cloud Gateway 基于 Reactor 和 WebFlux,性能优于 Zuul 1.x,且支持灵活的断言(Predicate)与过滤器(Filter)模型。
3.2 创建 Gateway 服务
新建项目,添加依赖(不要引入 spring-boot-starter-web,因为 Gateway 基于 WebFlux):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
启动类无需特殊注解。
application.yml:
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service # 使用 Eureka 服务名
predicates:
- Path=/user/**
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
此时访问 http://localhost:9000/user/1,网关会将请求转发到 user-service 的 /user/1 接口。lb:// 前缀表示启用负载均衡。
3.3 路由配置与断言
Gateway 通过 predicates 匹配请求,常用断言工厂:
Path=/api/**:路径匹配Method=GET,POST:请求方法Header=X-Request-Id, \d+:请求头匹配Query=foo, \w+:查询参数Cookie=name, value:Cookie 匹配
示例:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/order/**
- Method=POST
- Header=Content-Type, application/json
匹配所有 /order/** 且 POST 方法、Content-Type 为 JSON 的请求。
3.4 过滤器与限流
过滤器在请求前后执行处理,分为内置和自定义两种。
- StripPrefix:
- StripPrefix=1可去掉路径第一段,如/user/1转发时变为/1。 - AddRequestHeader:
- AddRequestHeader=X-Custom, MyValue。 - RequestRateLimiter:需结合 Redis 实现令牌桶限流。
配置限流过滤器示例(需要添加 spring-boot-starter-data-redis-reactive 依赖):
spring:
cloud:
gateway:
routes:
- id: rate-limited-route
uri: lb://user-service
predicates:
- Path=/user/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
data:
redis:
host: localhost
定义 KeyResolver Bean(按请求 IP 限流):
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
全局过滤器可跨路由生效,实现 GlobalFilter 接口添加日志、鉴权等逻辑。
4. 整合与最佳实践
将上述三个组件整合到一个微服务脚手架中,启动顺序:Eureka Server → Config Server → 业务服务(含 Gateway)。Gateway 自身也可以作为一个 Eureka 客户端,并从 Config Server 拉取路由配置,实现动态路由。
核心要点
- 服务命名:全部小写,使用连字符分隔,与配置文件保持一致。
- 健康检查:为所有服务添加 Actuator 依赖并暴露
health端点,便于监控。 - 配置分层:利用 Spring Cloud Config 的 profile 与环境管理,避免环境间硬编码。
- 网关高可用:Gateway 同样部署多实例,前端用 Nginx 反向代理。
- 安全加固:网关层统一处理跨域、限流、认证,减轻业务服务负担。
常见问题
- 服务无法注册:检查 Eureka 服务端端口和路径,客户端
defaultZone是否正确,网络是否互通。 - 配置拉取失败:确认 Config Server 可用,
bootstrap.yml配置是否正确,仓库路径与分支标签。 - 网关路由 404:检查路由断言是否匹配,服务是否在注册中心,
lb://写法是否正确。
结语
通过本教程,你已掌握 Spring Cloud 微服务中服务发现、配置管理与 API 网关的核心配置和使用方法。这三者是生产就绪微服务架构的基石。建议后续继续学习熔断限流(Resilience4j/Sentinel)、链路追踪(Sleuth+Zipkin/SkyWalking)等内容,构建完整的云原生应用。