Spring Cloud Gateway 核心架构
Spring Cloud Gateway 是 Spring 官方基于 Spring WebFlux + Reactor Netty 打造的 API 网关,替代 Netflix Zuul。理解它的核心架构,是后续源码阅读与生产调优的基础。
网关的职责
客户端 ──▶ 网关 ──▶ 微服务集群
│
├─ 路由转发(核心)
├─ 鉴权(统一入口)
├─ 限流熔断(保护下游)
├─ 日志监控(全链路)
├─ 跨域/CORS
└─ 灰度发布(权重路由)网关把"每个服务都要做"的横切关注点收敛到一层,业务服务只关心业务。
核心三元组:Route / Predicate / Filter
Gateway 的一切围绕三个概念:
| 概念 | 作用 | 类比 |
|---|---|---|
| Route(路由) | 一组路由规则:ID + 目标 URI + 条件 + 过滤器 | if 语句 |
| Predicate(谓词) | 请求匹配条件(路径、头、方法……) | if 条件 |
| Filter(过滤器) | 请求/响应的横切处理 | 中间件 |
一个 Route 的定义:
┌────────────────────────────────────┐
│ id: order-route │
│ uri: lb://order-service │ ← 转发目标
│ predicates: Path=/api/order/** │ ← 匹配条件
│ filters: StripPrefix=2, AddRequestHeader=x-token,{header} │ ← 处理
└────────────────────────────────────┘Route 组成
java
public class Route {
private String id; // 路由 ID
private URI uri; // 目标地址(http:// / lb:// 等)
private int order; // 路由优先级
private Predicate<ServerWebExchange> predicate; // 匹配条件
private List<GatewayFilter> gatewayFilters; // 路由级过滤器
private Map<String, Object> metadata; // 元数据
}Predicate 的作用
谓词返回 true/false:请求命中该谓词,则该 Route 生效。多个谓词用 AND 组合(全部通过才匹配)。
Filter 的两级体系
GatewayFilter(路由级):
只作用于指定路由
由 FilterFactory 工厂创建,通过配置声明
GlobalFilter(全局级):
作用于所有请求
实现 GlobalFilter + Ordered 接口,Spring 自动装配请求处理整体流程
核心组件
DispatcherHandler(WebFlux 入口)
└── HandlerMapping(路由映射器)
└── RoutePredicateHandlerMapping(Gateway 的路由映射器)
└── HandlerAdapter(处理器适配器)
└── SimpleHandlerAdapter
└── HandlerResultHandler(结果处理)完整执行链路
1. 请求进入 Netty → Spring WebFlux
│
2. DispatcherHandler.handle()
│
3. RoutePredicateHandlerMapping.getHandlerInternal()
│ 遍历所有 Route,用 Predicate 匹配
│ 命中 → 返回 FilteringWebHandler(处理器)
│ 未命中 → 404
│
4. FilteringWebHandler.handle()
│ 组装过滤器链:
│ GlobalFilter(全局)+ Route 的 GatewayFilter(路由级)
│ 按 Order 排序,依次执行
│
5. 过滤器链执行
│ 前向:修改请求(加头/重写路径/鉴权/限流…)
│ 末端:NettyRoutingFilter 转发到下游服务
│
6. 下游响应返回
│
7. 过滤器链反向执行(响应阶段)
│ 修改响应(加头/缓存/日志…)
│
8. 返回客户端请求 ──▶ Filter1 ──▶ Filter2 ──▶ ... ──▶ NettyRoutingFilter ──▶ 下游
│
响应 ◀── Filter1 ◀── Filter2 ◀── ... ◀────── 下游响应关键组件详述
RoutePredicateHandlerMapping
负责"请求 → 路由"的匹配:
java
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final RouteLocator routeLocator; // 路由数据源
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// 1. 从 RouteLocator 取全部路由
// 2. 按 order 排序
// 3. 逐个用 predicate 匹配请求
return this.routeLocator.getRoutes()
.filter(route -> route.getPredicate().test(exchange))
.next() // 取第一个命中
.map(route -> {
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);
return new FilteringWebHandler(route); // 返回处理器
});
}
}FilteringWebHandler
组装过滤器链并执行:
java
public class FilteringWebHandler implements WebHandler {
private final List<GatewayFilter> globalFilters; // 所有 GlobalFilter
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// 1. 路由级过滤器
List<GatewayFilter> gatewayFilters = route.getFilters();
// 2. 合并全局过滤器
List<GatewayFilter> all = combine(globalFilters, gatewayFilters);
// 3. 排序(Order 值小的先执行)
AnnotationAwareOrderComparator.sort(all);
// 4. 构建责任链并执行
return new DefaultGatewayFilterChain(all).filter(exchange);
}
}过滤器链(GatewayFilterChain)
责任链模式:
java
public class DefaultGatewayFilterChain implements GatewayFilterChain {
private final List<GatewayFilter> filters;
private final int index; // 当前执行位置
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
// 依次取下一个过滤器执行
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
return filter.filter(exchange, chain); // 前向调用
}
return Mono.empty(); // 链结束
}
}过滤器时序
java
@Component
public class OrderFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 前向逻辑(请求阶段)
System.out.println("before: " + exchange.getRequest().getURI());
return chain.filter(exchange) // 继续执行下一个过滤器
.then(Mono.fromRunnable(() -> {
// 响应阶段(返回后执行)
System.out.println("after");
}));
}
}URI 协议与负载均衡
| 协议 | 含义 |
|---|---|
http://host:port | 直连固定地址 |
https://host:port | HTTPS 直连 |
lb://service-name | 通过注册中心(LoadBalancer)选择实例 |
ws:// / wss:// | WebSocket 代理 |
no:// | 仅做统一网关(不转发) |
yaml
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service # 服务发现 + 负载均衡
predicates:
- Path=/api/order/**lb:// 需要引入注册中心(Nacos/Eureka)+ LoadBalancer,Gateway 启动时注册到 DiscoveryClientRouteDefinitionLocator。
与 Zuul 的对比
| 对比 | Spring Cloud Gateway | Netflix Zuul 1.x |
|---|---|---|
| 底层 | WebFlux + Netty(Reactive) | Servlet + Tomcat(阻塞) |
| 性能 | 高(非阻塞) | 一般(线程池阻塞) |
| 长连接 | 支持(WebSocket) | 支持有限 |
| 编程模型 | 响应式 | 同步 |
| 维护状态 | 活跃演进 | 维护模式 |
| 路由配置 | YAML/Java 均可 | YAML/注解 |
Zuul 2.x 也支持 Netty,但生态与演进远不如 Gateway,新项目直接选 Gateway。
配置中心动态路由
路由可通过配置中心(Nacos Config)动态管理,无需重启:
yaml
# Nacos 配置
spring:
cloud:
gateway:
routes:
- id: dynamic-route
uri: lb://new-service
predicates:
- Path=/api/new/**配置变更 → 网关 RefreshRoutesEvent → 路由重新加载。也可用 Redis 实现动态路由(参考高级主题)。
常见问题
- 路由不生效? 检查谓词是否匹配、路由优先级(order)、
lb://是否可解析到注册中心实例。 - Gateway 与 Spring MVC 冲突? Gateway 基于 WebFlux,不能与 spring-boot-starter-web(MVC)同工程共存(两者抢 DispatcherServlet),需排除。
- 全局过滤器与路由过滤器顺序? 全部合并后按
Ordered排序,GlobalFilter 默认优先级更高。 - 为什么 Gateway 要求 Reactive? 非阻塞 + 高吞吐是网关的核心诉求,阻塞式线程模型扛不住大规模流量。