<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Cloud Gateway 源碼剖析之Predicate謂詞詳解

          共 15686字,需瀏覽 32分鐘

           ·

          2021-04-04 08:41

          0d1903203cd21ee75a56d88f0b199683.webp

          點(diǎn)擊上方老周聊架構(gòu)關(guān)注我


          一、前言

          我們上一篇?Spring Cloud Gateway 源碼剖析之Route數(shù)據(jù)模型?中講到了 Route 數(shù)據(jù)模型,其中有 Predicate 屬性。

          80b9aa4f3d8637ad828fcb0fcca49711.webp

          這一篇我們就來(lái)講一講 Predicate 謂詞相關(guān)源碼。Predicate 對(duì)象是由 RoutePredicateFactory 工廠類創(chuàng)建,那我們就來(lái)看下 RoutePredicateFactory 是如何創(chuàng)建 Predicate 的。
          c938d6df9e8aa9b3883b1a1d26b03782.webp

          二、RoutePredicateFactory

          從上圖可知

          • #name() 默認(rèn)方法,調(diào)用 NameUtils#normalizePredicateName(Class) 方法,獲得 RoutePredicateFactory 的名字。該方法截取類名前半段,例如 QueryRoutePredicateFactory 的結(jié)果為 Query 。

          • #apply() 接口方法,創(chuàng)建 Predicate 。

          可以直接看到處理器類與相關(guān)謂詞工廠類如下

          aef2b1194a512598e948715de10262ea.webp

          這里再對(duì)相關(guān)謂詞工廠進(jìn)行分類:
          56ceac76b8edb6a266811a09fc8f5740.webp

          2.1 AfterRoutePredicateFactory

          • Route 匹配 :請(qǐng)求時(shí)間滿足在配置時(shí)間之后

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?after_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?After=2017-01-20T17:42:47.789-07:00[America/Denver]
          • 代碼:

            public?Predicate<ServerWebExchange>?apply(AfterRoutePredicateFactory.Config?config)?{
            ????ZonedDateTime?datetime?=?config.getDatetime();
            ????return?(exchange)?->?{
            ????????ZonedDateTime?now?=?ZonedDateTime.now();
            ????????return?now.isAfter(datetime);
            ????};
            }

          2.2 BeforeRoutePredicateFactory

          • Route 匹配 :請(qǐng)求時(shí)間滿足在配置時(shí)間之前

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?before_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Before=2017-01-20T17:42:47.789-07:00[America/Denver]
          • 代碼:

            public?Predicate<ServerWebExchange>?apply(BeforeRoutePredicateFactory.Config?config)?{
            ????ZonedDateTime?datetime?=?config.getDatetime();
            ????return?(exchange)?->?{
            ????????ZonedDateTime?now?=?ZonedDateTime.now();
            ????????return?now.isBefore(datetime);
            ????};
            }

          2.3 BetweenRoutePredicateFactory

          • Route 匹配 :請(qǐng)求時(shí)間滿足在配置時(shí)間之間

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?between_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Betweeen=2017-01-20T17:42:47.789-07:00[America/Denver],?2017-01-21T17:42:47.789-07:00[America/Denver]
          • 代碼:

            public?Predicate<ServerWebExchange>?apply(BetweenRoutePredicateFactory.Config?config)?{
            ????ZonedDateTime?datetime1?=?config.datetime1;
            ????ZonedDateTime?datetime2?=?config.datetime2;
            ????Assert.isTrue(datetime1.isBefore(datetime2),?config.datetime1?+?"?must?be?before?"?+?config.datetime2);
            ????return?(exchange)?->?{
            ????????ZonedDateTime?now?=?ZonedDateTime.now();
            ????????return?now.isAfter(datetime1)?&&?now.isBefore(datetime2);
            ????};
            }

          2.4 CookieRoutePredicateFactory

          • Route 匹配 :請(qǐng)求指定 Cookie 正則匹配指定值

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?cookie_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Cookie=chocolate,?ch.p
          • 代碼:

            public Predicate<ServerWebExchange> apply(CookieRoutePredicateFactory.Config config) {    return (exchange) -> {        List<HttpCookie> cookies = (List)exchange.getRequest().getCookies().get(config.name);        if (cookies == null) {            return false;        } else {            Iterator var3 = cookies.iterator();
            HttpCookie cookie; do { if (!var3.hasNext()) { return false; }
            cookie = (HttpCookie)var3.next(); } while(!cookie.getValue().matches(config.regexp));
            return true; } };}

          2.5 HeaderRoutePredicateFactory

          • Route 匹配 :請(qǐng)求頭滿足匹配

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?header_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Header=X-Request-Id,?\d+
          • 代碼:

            public?Predicate<ServerWebExchange>?apply(HeaderRoutePredicateFactory.Config?config)?{
            ????boolean?hasRegex?=?!StringUtils.isEmpty(config.regexp);
            ????return?(exchange)?->?{
            ????????List<String>?values?=?(List)exchange.getRequest().getHeaders().getOrDefault(config.header,?Collections.emptyList());
            ????????if?(values.isEmpty())?{
            ????????????return?false;
            ????????}?else?{
            ????????????return?hasRegex???values.stream().anyMatch((value)?->?{
            ????????????????return?value.matches(config.regexp);
            ????????????})?:?true;
            ????????}
            ????};
            }

          2.6 HostRoutePredicateFactory

          • Route 匹配 :請(qǐng)求 Host 匹配指定值

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?host_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Host=**.somehost.org
          • 代碼:

            public?Predicate<ServerWebExchange>?apply(HostRoutePredicateFactory.Config?config)?{
            ????return?(exchange)?->?{
            ????????String?host?=?exchange.getRequest().getHeaders().getFirst("Host");
            ????????Optional<String>?optionalPattern?=?config.getPatterns().stream().filter((pattern)?->?{
            ????????????return?this.pathMatcher.match(pattern,?host);
            ????????}).findFirst();
            ????????if?(optionalPattern.isPresent())?{
            ????????????Map<String,?String>?variables?=?this.pathMatcher.extractUriTemplateVariables((String)optionalPattern.get(),?host);
            ????????????ServerWebExchangeUtils.putUriTemplateVariables(exchange,?variables);
            ????????????return?true;
            ????????}?else?{
            ????????????return?false;
            ????????}
            ????};
            }

          2.7 MethodRoutePredicateFactory

          • Route 匹配 :請(qǐng)求 Method 匹配指定值

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?method_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Method=GET
          • 代碼:

            public?Predicate<ServerWebExchange>?apply(MethodRoutePredicateFactory.Config?config)?{
            ????return?(exchange)?->?{
            ????????HttpMethod?requestMethod?=?exchange.getRequest().getMethod();
            ????????return?requestMethod?==?config.getMethod();
            ????};
            }

          2.8 PathRoutePredicateFactory

          • Route 匹配 :請(qǐng)求 Path 匹配指定值

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?host_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Path=/foo/{segment}
          • 代碼:

            public Predicate<ServerWebExchange> apply(PathRoutePredicateFactory.Config config) {    ArrayList<PathPattern> pathPatterns = new ArrayList();    synchronized(this.pathPatternParser) {        this.pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchOptionalTrailingSeparator());        config.getPatterns().forEach((pattern) -> {            PathPattern pathPattern = this.pathPatternParser.parse(pattern);            pathPatterns.add(pathPattern);        });    }
            return (exchange) -> { PathContainer path = PathContainer.parsePath(exchange.getRequest().getURI().getPath()); Optional<PathPattern> optionalPathPattern = pathPatterns.stream().filter((pattern) -> { return pattern.matches(path); }).findFirst(); if (optionalPathPattern.isPresent()) { PathPattern pathPattern = (PathPattern)optionalPathPattern.get(); traceMatch("Pattern", pathPattern.getPatternString(), path, true); PathMatchInfo pathMatchInfo = pathPattern.matchAndExtract(path); ServerWebExchangeUtils.putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables()); return true; } else { traceMatch("Pattern", config.getPatterns(), path, false); return false; } };}

          2.9 QueryRoutePredicateFactory

          • Route 匹配 :請(qǐng)求 QueryParam 匹配指定值

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?query_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?Query=baz
            ????????-?Query=foo,?ba.
          • 代碼:

            public Predicate<ServerWebExchange> apply(QueryRoutePredicateFactory.Config config) {    return (exchange) -> {        if (!StringUtils.hasText(config.regexp)) {            return exchange.getRequest().getQueryParams().containsKey(config.param);        } else {            List<String> values = (List)exchange.getRequest().getQueryParams().get(config.param);            if (values == null) {                return false;            } else {                Iterator var3 = values.iterator();
            String value; do { if (!var3.hasNext()) { return false; }
            value = (String)var3.next(); } while(value == null || !value.matches(config.regexp));
            return true; } } };}

          2.10 RemoteAddrRoutePredicateFactory

          • Route 匹配 :請(qǐng)求來(lái)源 IP 在指定范圍內(nèi)

          • 配置:

            spring:
            ??cloud:
            ????gateway:
            ??????routes:
            ??????-?id:?remoteaddr_route
            ????????uri:?http://example.org
            ????????predicates:
            ????????-?RemoteAddr=192.168.1.1/24
          • 代碼:

            public Predicate<ServerWebExchange> apply(RemoteAddrRoutePredicateFactory.Config config) {    List<IpSubnetFilterRule> sources = this.convert(config.sources);    return (exchange) -> {        InetSocketAddress remoteAddress = config.remoteAddressResolver.resolve(exchange);        if (remoteAddress != null && remoteAddress.getAddress() != null) {            String hostAddress = remoteAddress.getAddress().getHostAddress();            String host = exchange.getRequest().getURI().getHost();            if (log.isDebugEnabled() && !hostAddress.equals(host)) {                log.debug("Remote addresses didn't match " + hostAddress + " != " + host);            }
            Iterator var6 = sources.iterator();
            while(var6.hasNext()) { IpSubnetFilterRule source = (IpSubnetFilterRule)var6.next(); if (source.matches(remoteAddress)) { return true; } } }
            return false; };}

          三、RoutePredicateHandlerMapping

          我們先來(lái)看下 Spring Cloud Gateway 官網(wǎng)提供的架構(gòu)圖:

          7bbf0c0d7d0db90e47060e29101bb220.webp

          上一節(jié)講完了常見分類的 Predicate 匹配規(guī)則,客戶端發(fā)送請(qǐng)求過(guò)來(lái),通過(guò) HandlerMapping 進(jìn)行 predicate 的匹配,匹配成功再進(jìn)行下面的處理。

          3.1 org.springframework.web.reactive.DispatcherHandler

          接收到請(qǐng)求,匹配 HandlerMapping ,此處會(huì)匹配到 RoutePredicateHandlerMapping。由于 Gateway 是構(gòu)建在 reactive 上的,所以這邊的 web 類型就是 reactive。

          public?class?DispatcherHandler?implements?WebHandler,?ApplicationContextAware?{
          ????private?static?final?Exception?HANDLER_NOT_FOUND_EXCEPTION;
          ????@Nullable
          ????private?List<HandlerMapping>?handlerMappings;
          ????@Nullable
          ????private?List<HandlerAdapter>?handlerAdapters;
          ????@Nullable
          ????private?List<HandlerResultHandler>?resultHandlers;

          ????public?Mono<Void>?handle(ServerWebExchange?exchange)?{
          ????????return?this.handlerMappings?==?null???this.createNotFoundError()?:?
          ????????//?順序使用?handlerMappings?獲得對(duì)應(yīng)的?WebHandler?
          ????????Flux.fromIterable(this.handlerMappings).concatMap((mapping)?->?{
          ????????????//?獲得?Handler?
          ????????????return?mapping.getHandler(exchange);
          ????????//?如果匹配不到 WebHandler ,返回 HANDLER_NOT_FOUND_EXCEPTION 。
          ????????}).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler)?->?{
          ????????????//?調(diào)用 invokeHandler()?方法,執(zhí)行 Handler 。
          ????????????return?this.invokeHandler(exchange,?handler);
          ????????}).flatMap((result)?->?{
          ????????????//?調(diào)用?handleResult()?方法,處理結(jié)果
          ????????????return?this.handleResult(exchange,?result);
          ????????});
          ????}

          ????...
          }

          繼續(xù)跟一下 invokeHandler() 方法:

          private?Mono<HandlerResult>?invokeHandler(ServerWebExchange?exchange,?Object?handler)?{
          ????if?(this.handlerAdapters?!=?null)?{
          ????????//?獲取Adapters, WebHandler 的處理器適配器。
          ????????Iterator?var3?=?this.handlerAdapters.iterator();

          ????????while(var3.hasNext())?{
          ????????????HandlerAdapter?handlerAdapter?=?(HandlerAdapter)var3.next();
          ????????????//?調(diào)用support方法?,是否支持?WebHandler
          ????????????if?(handlerAdapter.supports(handler))?{
          ????????????????//?調(diào)用handle?方法,執(zhí)行處理器
          ????????????????return?handlerAdapter.handle(exchange,?handler);
          ????????????}
          ????????}
          ????}

          ????return?Mono.error(new?IllegalStateException("No?HandlerAdapter:?"?+?handler));
          }
          public?boolean?supports(Object?handler)?{
          ????return?WebHandler.class.isAssignableFrom(handler.getClass());
          }
          public?Mono<HandlerResult>?handle(ServerWebExchange?exchange,?Object?handler)?{
          ????WebHandler?webHandler?=?(WebHandler)handler;
          ????//?執(zhí)行處理器。例如,WebHandler 為 FilteringWebHandler 時(shí),獲得 Route 的 GatewayFilter 數(shù)組,創(chuàng)建 GatewayFilterChain 處理請(qǐng)求。
          ????Mono<Void>?mono?=?webHandler.handle(exchange);
          ????//?在 WebHandler 執(zhí)行完后?#then(Mongo),然后返回 Mono.empty()?。
          ????return?mono.then(Mono.empty());
          }

          SimpleHandlerAdapter 返回的是 Mono.empty() ,所以不會(huì)觸發(fā)該方法。

          private?Mono<Void>?handleResult(ServerWebExchange?exchange,?HandlerResult?result)?{
          ????return?this.getResultHandler(result).handleResult(exchange,?result).onErrorResume((ex)?->?{
          ????????return?result.applyExceptionHandler(ex).flatMap((exceptionResult)?->?{
          ????????????return?this.getResultHandler(exceptionResult).handleResult(exchange,?exceptionResult);
          ????????});
          ????});
          }

          3.2 org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping

          接收到請(qǐng)求,匹配 Route ,并返回處理 Route 的 FilteringWebHandler。

          SimpleHandlerAdapter#handle(ServerWebExchange, Object) 調(diào)用 FilteringWebHandler#handle(ServerWebExchange) 方法,處理請(qǐng)求。

          public?class?RoutePredicateHandlerMapping?extends?AbstractHandlerMapping?{
          ????private?final?FilteringWebHandler?webHandler;
          ????private?final?RouteLocator?routeLocator;
          ????private?final?Integer?managmentPort;

          ????public?RoutePredicateHandlerMapping(FilteringWebHandler?webHandler,?RouteLocator?routeLocator,?GlobalCorsProperties?globalCorsProperties,?Environment?environment)?{
          ????????this.webHandler?=?webHandler;
          ????????this.routeLocator?=?routeLocator;
          ????????if?(environment.containsProperty("management.server.port"))?{
          ????????????this.managmentPort?=?new?Integer(environment.getProperty("management.server.port"));
          ????????}?else?{
          ????????????this.managmentPort?=?null;
          ????????}
          ????????//?RequestMappingHandlerMapping?之后
          ????????this.setOrder(1);
          ????????this.setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
          ????}

          ????protected?Mono<?>?getHandlerInternal(ServerWebExchange?exchange)?{
          ????????if?(this.managmentPort?!=?null?&&?exchange.getRequest().getURI().getPort()?==?this.managmentPort)?{
          ????????????return?Mono.empty();
          ????????}?else?{
          ????????????//?設(shè)置?GATEWAY_HANDLER_MAPPER_ATTR?為?
          ????????????RoutePredicateHandlerMappingexchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR,?this.getSimpleName());
          ????????????//?匹配路由
          ????????????return?this.lookupRoute(exchange).flatMap((r)?->?{
          ????????????????exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
          ????????????????if?(this.logger.isDebugEnabled())?{
          ????????????????????this.logger.debug("Mapping?["?+?this.getExchangeDesc(exchange)?+?"]?to?"?+?r);
          ????????????????}
          ????????????????//?設(shè)置?GATEWAY_ROUTE_ATTR?為?匹配的?Route
          ????????????????exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR,?r);
          ????????????????return?Mono.just(this.webHandler);
          ????????????}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(()?->?{?//匹配不到返回
          ????????????????exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
          ????????????????if?(this.logger.isTraceEnabled())?{
          ????????????????????this.logger.trace("No?RouteDefinition?found?for?["?+?this.getExchangeDesc(exchange)?+?"]");
          ????????????????}

          ????????????})));
          ????????}
          ????}
          }

          跟一下 lookupRoute 匹配路由,這個(gè)方法是網(wǎng)關(guān)的核心,像我們自研的網(wǎng)關(guān),如果你剛接手公司中的網(wǎng)關(guān)項(xiàng)目,找到匹配路由再展開,能幫你省很多時(shí)間,快速熟悉公司中網(wǎng)關(guān)的項(xiàng)目。

          protected?Mono<Route>?lookupRoute(ServerWebExchange?exchange)?{
          ????//?獲取所有路由
          ????return?this.routeLocator.getRoutes().concatMap((route)?->?{
          ????????return?Mono.just(route).filterWhen((r)?->?{
          ????????????exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR,?r.getId());
          ????????????//?并調(diào)用 Predicate#apply(ServerWebExchange)?方法,順序匹配一個(gè) Route。
          ????????????return?(Publisher)r.getPredicate().apply(exchange);
          ????????//?未來(lái)會(huì)增加匹配過(guò)程中發(fā)生異常的處理。目前,任何一個(gè) Predicate#test(ServerWebExchange)?的方法調(diào)用發(fā)生異常時(shí),都會(huì)導(dǎo)致匹配不到 Route。一定要注意。??????
          ????????}).doOnError((e)?->?{
          ????????????this.logger.error("Error?applying?predicate?for?route:?"?+?route.getId(),?e);
          ????????}).onErrorResume((e)?->?{
          ????????????return?Mono.empty();
          ????????});
          ????}).next().map((route)?->?{
          ????????if?(this.logger.isDebugEnabled())?{
          ????????????this.logger.debug("Route?matched:?"?+?route.getId());
          ????????}

          ????????this.validateRoute(route,?exchange);
          ????????return?route;
          ????});
          }

          3.3 org.springframework.cloud.gateway.handler.FilteringWebHandler

          獲得 Route 的 GatewayFilter 數(shù)組,創(chuàng)建 GatewayFilterChain 處理請(qǐng)求。這里我們放到下一篇來(lái)講,下一篇也很重要,從原理來(lái)說(shuō)也不是很難理解,就是一個(gè)過(guò)濾器鏈。但從 Gateway 的兩大核心:路由+過(guò)濾鏈來(lái)說(shuō),這又很重要。



          歡迎大家關(guān)注我的公眾號(hào)【老周聊架構(gòu)】,Java后端主流技術(shù)棧的原理、源碼分析、架構(gòu)以及各種互聯(lián)網(wǎng)高并發(fā)、高性能、高可用的解決方案。

          喜歡的話,點(diǎn)贊、再看、分享三連。

          490d4462a56e78f1fef959e035c96863.webp

          點(diǎn)個(gè)在看你最好看



          瀏覽 74
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧洲亚洲日本在线 | 大香蕉精品网 | 四虎福利 | 欧美日韩在线观看中文字幕 | TS人妖一区二区三区 |