Spring Cloud Alibaba - 25 Gateway-路由断言工厂Route Predicate Factories谓词工厂示例及源码解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
网络型负载均衡 NLB,每月750个小时 15LCU
云解析 DNS,旗舰版 1个月
简介: Spring Cloud Alibaba - 25 Gateway-路由断言工厂Route Predicate Factories谓词工厂示例及源码解析

6735aa4777de402592fbe82e8b40ee3d.png

官网


https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories


efda0395c2c841c290c57e6b7fe8c02c.png


Spring Cloud Gateway 将路由匹配为 Spring WebFluxHandlerMapping基础架构的一部分。Spring Cloud Gateway 包含许多内置的路由谓词工厂。所有这些谓词都匹配 HTTP 请求的不同属性。我们可以将多个路由谓词工厂与逻辑and语句结合起来。


The After Route Predicate Factory


https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-after-route-predicate-factory


bc324e779555424785f12365cfaa960b.png


小栗子


我们还是继续老工程 ,启动

artisan-cloud-gateway 【8888】

artisan-cloud-gateway-order

artisan-cloud-gateway-product


网关配置

application-after_route.yml

#  网关的After谓词,对应的源码处理AfterRoutePredicateFactory
#作用: 经过网关的所有请求 当前时间>比After阈值  就进行转发
#现在我们是2022年了 currentTime<After阈值,所以网关不会进行转发,而返回404spring:
spring:
  cloud:
    gateway: #gateway
      routes:
        - id: after_route  # id 确保唯一
          uri: lb://artisan-cloud-gateway-order  #  nacos上的 注册地址
          predicates:
            - After=2025-02-13T18:27:28.309+08:00[Asia/Shanghai]


currentTime<After阈值,所以网关不会进行转发 .

激活配置文件


ed80b0cf416f4559850e6eb9d86a2dd9.png

【测试】

86d3854e4a0d49d58941c26d3d8e8fab.png

符合预期。

如果我们改下时间呢?f4ed71bd62d1431d9be69770f38d2be3.png


550cb642210f44af8d7e2ef186675c18.png

AfterRoutePredicateFactory源码

public class AfterRoutePredicateFactory
    extends AbstractRoutePredicateFactory<AfterRoutePredicateFactory.Config> {
  /**
   * DateTime key.
   */
  public static final String DATETIME_KEY = "datetime";
  public AfterRoutePredicateFactory() {
    super(Config.class);
  }
  @Override
  public List<String> shortcutFieldOrder() {
    return Collections.singletonList(DATETIME_KEY);
  }
  @Override
  public Predicate<ServerWebExchange> apply(Config config) {
    return new GatewayPredicate() {
      @Override
      public boolean test(ServerWebExchange serverWebExchange) {
        final ZonedDateTime now = ZonedDateTime.now();
        return now.isAfter(config.getDatetime());
      }
      @Override
      public String toString() {
        return String.format("After: %s", config.getDatetime());
      }
    };
  }
  public static class Config {
    @NotNull
    private ZonedDateTime datetime;
    public ZonedDateTime getDatetime() {
      return datetime;
    }
    public void setDatetime(ZonedDateTime datetime) {
      this.datetime = datetime;
    }
  }
}


核心方法,apply,比较简单。


The Before Route Predicate Factory


https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-before-route-predicate-factory


7c31b93da03041d487716752eea94fcd.png


小栗子

application-before_route.yml

#目的:测试网关的Before谓词,对应的源码处理BeforeRoutePredicateFactory
#作用: 经过网关的所有请求当前时间 比Before=2021-02-13T18:27:28.309+08:00[Asia/Shanghai] 小  就进行转发
#现在2022年了 时间比配置的阈值大,所以我们不会进行转发,而返回404
#2021-02-13T18:27:28.309+08:00[Asia/Shanghai] 这个时间怎么获取的呢? --- System.out.println(ZonedDateTime.now())
spring:
  cloud:
    gateway: #gateway
      routes:
        - id: before_route  # id 确保唯一
          uri: lb://artisan-cloud-gateway-order
          predicates:
            - Before=2023-02-13T18:27:28.309+08:00[Asia/Shanghai]


BeforeRoutePredicateFactory源码

public class BeforeRoutePredicateFactory
    extends AbstractRoutePredicateFactory<BeforeRoutePredicateFactory.Config> {
  /**
   * DateTime key.
   */
  public static final String DATETIME_KEY = "datetime";
  public BeforeRoutePredicateFactory() {
    super(Config.class);
  }
  @Override
  public List<String> shortcutFieldOrder() {
    return Collections.singletonList(DATETIME_KEY);
  }
  @Override
  public Predicate<ServerWebExchange> apply(Config config) {
    return new GatewayPredicate() {
      @Override
      public boolean test(ServerWebExchange serverWebExchange) {
        final ZonedDateTime now = ZonedDateTime.now();
        return now.isBefore(config.getDatetime());
      }
      @Override
      public String toString() {
        return String.format("Before: %s", config.getDatetime());
      }
    };
  }
  public static class Config {
    private ZonedDateTime datetime;
    public ZonedDateTime getDatetime() {
      return datetime;
    }
    public void setDatetime(ZonedDateTime datetime) {
      this.datetime = datetime;
    }
  }
}


The Between Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-between-route-predicate-factory

8ed70d6a35d0441faacc62b599a8b32f.png


小栗子

application-between-route.yml

# Between谓词  BetweenRoutePredicateFactory
# 就是经过网关请求的当前时间 currentTime 满足
# Between startTime < currentTime < Between EndTime 才进行转发
spring:
  cloud:
    gateway:
      routes:
        - id: between-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order  # 这里可以使用负载均衡的写法
          predicates:
            - Between=2020-02-13T18:27:28.309+08:00[Asia/Shanghai],2025-02-13T18:27:28.309+08:00[Asia/Shanghai]


BetweenRoutePredicateFactory源码

public class BetweenRoutePredicateFactory
    extends AbstractRoutePredicateFactory<BetweenRoutePredicateFactory.Config> {
  /**
   * DateTime 1 key.
   */
  public static final String DATETIME1_KEY = "datetime1";
  /**
   * DateTime 2 key.
   */
  public static final String DATETIME2_KEY = "datetime2";
  public BetweenRoutePredicateFactory() {
    super(Config.class);
  }
  @Override
  public List<String> shortcutFieldOrder() {
    return Arrays.asList(DATETIME1_KEY, DATETIME2_KEY);
  }
  @Override
  public Predicate<ServerWebExchange> apply(Config config) {
    Assert.isTrue(config.getDatetime1().isBefore(config.getDatetime2()),
        config.getDatetime1() + " must be before " + config.getDatetime2());
    return new GatewayPredicate() {
      @Override
      public boolean test(ServerWebExchange serverWebExchange) {
        final ZonedDateTime now = ZonedDateTime.now();
        return now.isAfter(config.getDatetime1())
            && now.isBefore(config.getDatetime2());
      }
      @Override
      public String toString() {
        return String.format("Between: %s and %s", config.getDatetime1(),
            config.getDatetime2());
      }
    };
  }
  @Validated
  public static class Config {
    @NotNull
    private ZonedDateTime datetime1;
    @NotNull
    private ZonedDateTime datetime2;
    public ZonedDateTime getDatetime1() {
      return datetime1;
    }
    public Config setDatetime1(ZonedDateTime datetime1) {
      this.datetime1 = datetime1;
      return this;
    }
    public ZonedDateTime getDatetime2() {
      return datetime2;
    }
    public Config setDatetime2(ZonedDateTime datetime2) {
      this.datetime2 = datetime2;
      return this;
    }
  }
}


The Cookie Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-cookie-route-predicate-factory


1a9555dc649d42f6aaec0595fdf94de0.png


小栗子

application-cookie-route.yml

#谓词 Cookie 源码  CookieRoutePredicateFactory
#表示通过网关的请求 必须带入包含了Cookie name=Company value=Artisan
#才转发请求
spring:
  cloud:
    gateway:
      routes:
        - id: cookie-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order  # 这里可以使用负载均衡的写法
          predicates:
            #当我们的请求中包含了Cookie name=Company value=Artisan
            #才转发请求
            - Cookie=Company,Artisan


CookieRoutePredicateFactory源码

核心方法

@Override
  public Predicate<ServerWebExchange> apply(Config config) {
    return new GatewayPredicate() {
      @Override
      public boolean test(ServerWebExchange exchange) {
        List<HttpCookie> cookies = exchange.getRequest().getCookies()
            .get(config.name);
        if (cookies == null) {
          return false;
        }
        for (HttpCookie cookie : cookies) {
          if (cookie.getValue().matches(config.regexp)) {
            return true;
          }
        }
        return false;
      }
      @Override
      public String toString() {
        return String.format("Cookie: name=%s regexp=%s", config.name,
            config.regexp);
      }
    };
  }



The Header Route Predicate Factory

https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-header-route-predicate-factory0ad5333f223d4a22a0fb84ed5d5ef0fc.png


小栗子

application-header-route.yml

#Header谓词   源码HeaderRoutePredicateFactory
#说明请求经过网关 必须带入
#header的k=X-Request-appId v=Artisan才会被转发
spring:
  cloud:
    gateway:
      routes:
        - id: header-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order
          predicates:
            - Header=X-Request-appId,Artisan

HeaderRoutePredicateFactory源码

@Override
  public Predicate<ServerWebExchange> apply(Config config) {
    boolean hasRegex = !StringUtils.isEmpty(config.regexp);
    return new GatewayPredicate() {
      @Override
      public boolean test(ServerWebExchange exchange) {
        List<String> values = exchange.getRequest().getHeaders()
            .getOrDefault(config.header, Collections.emptyList());
        if (values.isEmpty()) {
          return false;
        }
        // values is now guaranteed to not be empty
        if (hasRegex) {
          // check if a header value matches
          return values.stream()
              .anyMatch(value -> value.matches(config.regexp));
        }
        // there is a value and since regexp is empty, we only check existence.
        return true;
      }
      @Override
      public String toString() {
        return String.format("Header: %s regexp=%s", config.header,
            config.regexp);
      }
    };
  }


The Host Route Predicate Factory


678c802c65564cefa96df513a115754b.png


#Host谓词  源码HostRoutePredicateFactory 
#说明请求http://localhost:8888/selectOrderInfoById/1的
#Host必须满足www.artisan.com:8888或者localhost:8888才会
#转发到http://artisan-cloud-gateway-order/selectOrderInfoById/1
#而127.0.0.1不会被转发
spring:
  cloud:
    gateway:
      routes:
        - id: host-route #id必须要唯一
          uri: lb://artisan-cloud-gateway-order
          predicates:
            - Host=www.artisan.com:8888,localhost:8888

The Method Route Predicate Factory


a612ecb296e848bcb081271a2e5dae64.png

#Http请求方法的谓词 Method 源码 MethodRoutePredicateFactory 
#表示经过网关的请求 只有post方式才能被转发
spring:
  cloud:
    gateway:
      routes:
       - id: method #id必须要唯一
         uri: lb://artisan-cloud-gateway-order
         predicates:
           #当前请求的方式 http://localhost:8888/selectOrderInfoById/1 是Post才会被转发
           #到http://artisan-cloud-gateway-order/selectOrderInfoById/1
           - Method=Post


The Path Route Predicate Factory


a03fe6b135eb44edb8b26610fecc7b79.png


850a282ecf414f619917dd85f063774c.png

The Query Route Predicate Factory

d565ec660b684e15bc0a66f82cab9719.png

3f7c72b678784e93a0c3a676d79c97d7.png


The RemoteAddr Route Predicate Factory


a51ee8e25a414238bf8a3dd99a655fea.png

The Weight Route Predicate Factory


755ac97c8a2a43dab5c0a11563f57af1.png


源码


https://github.com/yangshangwei/SpringCloudAlibabMaster

相关文章
|
23天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
60 2
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
166 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
108 62
|
2月前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
62 2
|
2月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
135 5
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第8天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建并配置 Spring Boot 项目,实现后端 API 和安全配置。接着,使用 Ant Design Pro Vue 脚手架创建前端项目,配置动态路由和菜单,并创建相应的页面组件。最后,通过具体实践心得,分享了版本兼容性、安全性、性能调优等注意事项,帮助读者快速搭建高效且易维护的应用框架。
49 3
|
2月前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第7天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建 Spring Boot 项目并配置 Spring Security。接着,实现后端 API 以提供菜单数据。在前端部分,使用 Ant Design Pro Vue 脚手架创建项目,并配置动态路由和菜单。最后,启动前后端服务,实现高效、美观且功能强大的应用框架。
55 2
|
2月前
|
人工智能 缓存 Java
深入解析Spring AI框架:在Java应用中实现智能化交互的关键
【10月更文挑战第12天】Spring AI 是 Spring 框架家族的新成员,旨在满足 Java 应用程序对人工智能集成的需求。它支持自然语言处理、图像识别等多种 AI 技术,并提供与云服务(如 OpenAI、Azure Cognitive Services)及本地模型的无缝集成。通过简单的配置和编码,开发者可轻松实现 AI 功能,同时应对模型切换、数据安全及性能优化等挑战。
157 3