在Spring Cloud Gateway中,默认添加的predicate是:PathRoutePredicateFactory。在Spring Cloud Gateway中有许多的Predicate,他们的功能各异。下面我们一起分析一下。
一、获取predicate
在RouteDefinitionRouteLocator类的getRoutes()方法中:
@Override
public Flux<Route> getRoutes() {
return this.routeDefinitionLocator.getRouteDefinitions()
.map(this::convertToRoute)
上面再获取到RouteDefinition后,会调用convertToRoute()方法,通过这个方法就是去获取了route中的predicates。
private Route convertToRoute(RouteDefinition routeDefinition) {
AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
我们进入combinePredicate方法中看下
private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
List<PredicateDefinition> predicates = routeDefinition.getPredicates();
AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));
for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {
AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
predicate = predicate.and(found);
}
return predicate;
}
可以看到方法中先获取第一个predicate,再获取第二个predicate,调用and方法整合两个predicate为一个predicate
二、整合predicate
整合代码为predicate的and方法
default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {
Objects.requireNonNull(other, "other must not be null");
return t -> Flux.zip(apply(t), other.apply(t))
.map(tuple -> tuple.getT1() && tuple.getT2());
}
整合中用到了Tuple2类,就是调用的时候,验证两个predicate的apply()方法是否都通过,做&&运算。通过这种方式重复整合,可以做到验证多个predicate。
三、predicates
Spring Cloud Gateway默认只用了一个Predicate,PathRoutePredicateFactory,其实还有其他Predicate可以使用,他们分别如下:
|
在某个时间点前有用的路由 |
|
在某个时间点后有用的路由 |
|
在两个时间点间有用的路由 |
|
用于云计算的路由(不动) |
|
验证cookie的路由 |
|
验证header的路由 |
|
验证host的路由 |
|
验证请求方式的路由 |
|
验证path的路由 |
|
验证请求参数的路由 |
|
验证body的路由 |
|
验证远程访问地址的路由 |
|
权重的路由 |
四、重点
需要说明的是,这些Predicate都是已经写好的代码,要填写适当的参数。例如验证header的路由,只能验证某个header是否为某个值,而且一旦使用,所有的route都要走这个路由规则。所以predicate是做通用配置用的,而不是用作个性化配置的。
五、使用方式举例
@Bean
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(normalizeRoutePredicateName(WeightRoutePredicateFactory.class));
predicate.addArg("weight.group", "serviceId");
properties.getPredicates().add(predicate);
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}