在Spring Cloud Gateway中,自定义GlobalFilter
实现动态路由规则的核心在于通过编程方式修改请求的URI或路由属性,并结合业务逻辑(如参数解析、服务发现等)动态确定目标服务地址。以下是具体实现方案及关键步骤:
一、实现原理
-
动态路由本质
通过
GlobalFilter
拦截请求,解析业务参数(如Token、路径变量等),动态修改ServerWebExchange
中的GATEWAY_REQUEST_URL_ATTR
属性,覆盖默认路由规则。 -
与内置过滤器的协作
自定义
GlobalFilter
需在RouteToRequestUrlFilter
(Order=10000)和ReactiveLoadBalancerClientFilter
(Order=10150)之间执行(即Order值介于两者之间),确保路由转换在负载均衡前生效。
二、实现步骤
1. 创建自定义GlobalFilter
java
@Component
@Slf4j
public class DynamicRouteFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取原始请求和路由信息
ServerHttpRequest request = exchange.getRequest();
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
// 2. 解析业务参数(如Token、路径参数等)
String token = request.getHeaders().getFirst("Authorization");
String targetService = parseTargetServiceFromToken(token); // 自定义解析逻辑
// 3. 动态构造目标URI(可从数据库/Redis/配置中心获取)
URI newUri = UriComponentsBuilder.fromUriString("http://" + targetService + ":8080")
.path(request.getPath().toString())
.build()
.toUri();
// 4. 修改请求属性,覆盖默认路由
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newUri);
log.info("动态路由至: {}", newUri);
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 10100; // 确保在RouteToRequestUrlFilter之后执行
}
}
关键点:
- 通过
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
覆盖目标URI。 - 若需负载均衡,可使用
lb://service-name
格式的URI,并确保Order值小于10150。
2. 动态路由数据源配置
-
从Redis获取路由规则
示例:根据路径参数
unitId
从Redis查询目标服务地址:vbnetprivate String getTargetHost(String unitId) { String key = "dynamic_route:" + unitId; return redisTemplate.opsForValue().get(key); // 返回格式如"192.168.1.100:8080" }
-
从数据库或配置中心加载
结合
RefreshRoutesEvent
事件动态更新路由表。
3. 配置动态路由支持
在application.yml
中启用服务发现(如Nacos/Eureka):
yaml
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 开启基于服务名的动态路由
lower-case-service-id: true
三、典型应用场景
-
基于Token的路由
解析JWT中的租户或系统标识,将请求路由至不同环境的服务实例。
-
灰度发布
根据请求头
X-Version
将流量分发至新版本服务。 -
调试路由
开发阶段强制将请求路由到本地调试服务(如
localhost:9012
)。
四、注意事项
-
执行顺序控制
确保自定义过滤器的Order值大于
RouteToRequestUrlFilter
(10000)但小于ReactiveLoadBalancerClientFilter
(10150)。 -
线程安全
GlobalFilter
是单例的,避免使用非线程安全的成员变量。 -
性能优化
动态路由查询(如Redis/Database)建议增加缓存,减少IO开销。
五、扩展方案
-
完全覆盖默认过滤器
通过
@Component(value = "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter")
覆盖内置过滤器,实现更复杂的路由逻辑。 -
结合配置中心
使用Nacos/Spring Cloud Config动态更新路由规则,无需重启网关。
通过上述方法,可灵活实现基于业务需求的动态路由,提升微服务架构的适应性。