如何在Spring Cloud Gateway中为Route.Builder设置断言?
Spring Cloud Gateway中Route.Builder添加断言的疑问
我不会展开过多细节(相关性不强且代码量较大),以下是我编写的接口:
@FunctionalInterface public interface RouteProcessor { // DocumentedEndpoint是我封装服务暴露端点的自定义类 Route.Builder process(Route.Builder routeInConstruction, DocumentedEndpoint endpoint); }
它的使用方式如下(仅为基础思路,非最终代码):
private void buildAndAddRoutesFrom(List<? extends DocumentedEndpoint> endpoints) { for (DocumentedEndpoint endpoint : endpoints) { Route.Builder routeBuilder = Route.builder(); for (RouteProcessor routeProcessor : routeProcessors) { routeBuilder = routeProcessor.process(routeBuilder, endpoint); } routeFlux = routeFlux.concatWith(Mono.just(routeBuilder.build())); // 此写法有待商榷,但暂不讨论 } }
以上内容并非重点。重点是我觉得Spring Cloud Gateway的源码设计存在优化空间,尤其是我不知道如何为构建中的Route添加断言。例如,假设我已创建了断言,该如何将其传入?
@Bean public RouteProcessor authenticationRouteProcessor() { return (routeInConstruction, endpoint) -> { AsyncPredicate<ServerWebExchange> newPredicate = AsyncPredicate.from(serverWebExchange -> serverWebExchange .getRequest() .getPath() .toString() .startsWith("/api/v1")); AsyncPredicate<ServerWebExchange> compoundPredicate = routeInConstruction.getPredicate().and(predicate); // 接下来该怎么做?
如何在Spring Cloud Gateway中为Route.Builder设置断言?难道只能通过调用这个私有构造方法来传入吗?
// 来自Route.AbstractBuilder public Route build() { Assert.notNull(this.id, "id can not be null"); Assert.notNull(this.uri, "uri can not be null"); AsyncPredicate<ServerWebExchange> predicate = getPredicate(); Assert.notNull(predicate, "predicate can not be null"); // Route包含断言,但Route.Builder却没有! return new Route(this.id, this.uri, this.order, predicate, this.gatewayFilters, this.metadata); }
Gateway的设计让我感到意外。我知道有个不错的and()方法可以用作设置器:
public Builder and(Predicate<ServerWebExchange> predicate) { Assert.notNull(this.predicate, "can not call and() on null predicate"); this.predicate = this.predicate.and(predicate); return this; }
但这种设置本质上是方法的副作用,让我觉得这更像是一种权宜之计,而非库使用者应采用的正规方式。更重要的是,我该如何向已有的断言中添加新断言?由于空值检查,初始断言应该已初始化,但以下写法无法生效:
@Bean public RouteProcessor basicPredicateProcessor() { return (routeInConstruction, endpoint) -> { routeInConstruction.and(serverWebExchange -> serverWebExchange .getRequest() .getPath() .toString() .startsWith("/api/v1")); return routeInConstruction; }; }
希望情况没有那么糟,是我遗漏了某些关键的源码片段。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

