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

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 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

相关文章
|
5月前
|
数据采集 人工智能 Java
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
DevDocs是一款基于智能爬虫技术的开源工具,支持1-5层深度网站结构解析,能将技术文档处理时间从数周缩短至几小时,并提供Markdown/JSON格式输出与AI工具无缝集成。
198 1
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
|
2月前
|
前端开发 Java API
Spring Cloud Gateway Server Web MVC报错“Unsupported transfer encoding: chunked”解决
本文解析了Spring Cloud Gateway中出现“Unsupported transfer encoding: chunked”错误的原因,指出该问题源于Feign依赖的HTTP客户端与服务端的`chunked`传输编码不兼容,并提供了具体的解决方案。通过规范Feign客户端接口的返回类型,可有效避免该异常,提升系统兼容性与稳定性。
168 0
|
3月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
143 1
|
2月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
|
2月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
105 0
|
3月前
|
缓存 监控 Java
说一说 SpringCloud Gateway 堆外内存溢出排查
我是小假 期待与你的下一次相遇 ~
446 5
|
3月前
|
Java API Nacos
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
3月前
|
Java 数据库 开发者
Spring Boot 框架超级详细总结及长尾关键词应用解析
本文深入讲解Spring Boot框架的核心概念、功能特性及实际应用,涵盖自动配置、独立运行、starter依赖等优势。通过Web开发、微服务架构、批处理等适用场景分析,结合在线书店实战案例,演示项目初始化、数据库设计、分层架构实现全流程。同时探讨热部署、多环境配置、缓存机制与事务管理等高级特性,助你高效掌握Spring Boot开发技巧。代码示例详尽,适合从入门到进阶的学习者。
1034 0
|
3月前
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
484 0

热门文章

最新文章

推荐镜像

更多
  • DNS