Weight 路由断言工厂需要两个参数:组(group)和权重(int 类型),注意,权重按组计算。语法如下:
Weight=组,权重
例如,为 https://weighthigh.org 地址创建两个路由,都放在 group1 分组下,如下:
spring: cloud: gateway: routes: - id: weight_high uri: https://weighthigh.org predicates: - Weight=group1, 8 - id: weight_low uri: https://weightlow.org predicates: - Weight=group1, 2
该路由将把 ~80% 的流量转发到 weighthigh.org,把 ~20% 的流量转发到 weighlow.org。
为了验证权重断言,我们需要启动两个订单服务,如下图:

上图中,两个订单服务的端口分别为 8081 和 18081。那么,如何在 IDEA 中启动两个订单服务呢?首先,修改一下 bootstrap.yml 配置文件,支持端口通过 JVM 参数指定,如下:
server:
port: ${port:8081}然后,右键“OrderApplication”选择“Copy Configuration...”复制一个运行配置,如下图:

然后,再次右键新复制的配置,点击“Edit Configuration...”编辑运行配置,添加 VM 参数(端口)等信息,如下图:

将“Gateway 搭建网关服务”项目的配置文件 bootstrap.yml 内容使用如下配置替换:
server: # 网关端口 port: 9000 spring: application: # 服务名称 name: gateway-demo01 cloud: # nacos nacos: discovery: server-addr: localhost:8848 username: nacos password: nacos group: DEFAULT_GROUP # 网关路由配置 gateway: # 网关路由配置 routes: # 路由id,自定义,只要唯一集合 - id: service-order1 # 路由的目标地址,lb 就是负载均衡,后面跟服务名,需要集成 nacos 等服务注册中心 uri: http://localhost:18081 # 路由断言,也就是判断请求是否符合路由规则的条件 predicates: # Weight断言:根据权重转发请求 - Weight=group1,2 # 路由id,自定义,只要唯一集合 - id: service-order2 # 路由的目标地址,lb 就是负载均衡,后面跟服务名 # 需要集成 nacos 等服务注册中心 lb://service-order uri: http://localhost:8081 # 路由断言,也就是判断请求是否符合路由规则的条件 predicates: # Weight断言:根据权重转发请求 - Weight=group1,8
上面配置中配置了两个路由,分别是 service-order1 和 service-order2,其中 80% 的请求将发送给 service-order2,20% 的请求将发送给 service-order1。
此时,我们通过 Postman 工具向网关发送 10 次请求,如下图:


从上图可知,有两个请求发送到了 OrderApplication2 服务,有 8 个请求发送到 OrderApplication 服务。
下面是 Weight 路由断言工厂源码:
package org.springframework.cloud.gateway.handler.predicate;
// ...
public class WeightRoutePredicateFactory extends AbstractRoutePredicateFactory<WeightConfig> implements ApplicationEventPublisherAware {
private static final Log log = LogFactory.getLog(WeightRoutePredicateFactory.class);
public static final String GROUP_KEY = WeightConfig.CONFIG_PREFIX + ".group";
public static final String WEIGHT_KEY = WeightConfig.CONFIG_PREFIX + ".weight";
private ApplicationEventPublisher publisher;
public WeightRoutePredicateFactory() {
super(WeightConfig.class);
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(GROUP_KEY, WEIGHT_KEY);
}
@Override
public String shortcutFieldPrefix() {
return WeightConfig.CONFIG_PREFIX;
}
@Override
public void beforeApply(WeightConfig config) {
if (publisher != null) {
publisher.publishEvent(new WeightDefinedEvent(this, config));
}
}
@Override
public Predicate<ServerWebExchange> apply(WeightConfig config) {
return exchange -> {
Map<String, String> weights = exchange.getAttributeOrDefault(WEIGHT_ATTR,
Collections.emptyMap());
String routeId = exchange.getAttribute(GATEWAY_PREDICATE_ROUTE_ATTR);
// 所有计算和与随机数的比较都在 WeightCalculatorWebFilter 中进行
// all calculations and comparison against random num happened in
// WeightCalculatorWebFilter
String group = config.getGroup();
if (weights.containsKey(group)) {
String chosenRoute = weights.get(group);
if (log.isTraceEnabled()) {
log.trace("in group weight: "+ group + ", current route: " + routeId +", chosen route: " + chosenRoute);
}
return routeId.equals(chosenRoute);
}
return false;
};
}
}