⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud-Gateway/route-definition-locator-intro/ 「芋道源码」欢迎转载,保留摘要,谢谢!

本文主要基于 Spring-Cloud-Gateway 2.0.X M4


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

阅读源码最好的方式,是使用 IDEA 进行调试 Spring Cloud Gateway 源码,不然会一脸懵逼。

胖友可以点击「芋道源码」扫码关注,回复 git019 关键字
获得艿艿添加了中文注释的 Spring Cloud Gateway 源码地址。

阅读源码很孤单,加入源码交流群,一起坚持!

1. 概述

本文主要对 路由定义定位器 RouteDefinitionLocator 做整体的认识

《Spring-Cloud-Gateway 源码解析 —— 网关初始化》 中,我们看到路由相关的组件 RouteDefinitionLocator / RouteLocator 的初始化。涉及到的类比较多,我们用下图重新梳理下 :


推荐 Spring Cloud 书籍

2. RouteDefinition

org.springframework.cloud.gateway.route.RouteDefinition ,路由定义。代码如下 :

@Validated
public class RouteDefinition {

@NotEmpty
private String id = UUID.randomUUID().toString();
/**
* 谓语定义数组
*/
@NotEmpty
@Valid
private List<PredicateDefinition> predicates = new ArrayList<>();
/**
* 过滤器定义数组
*/
@Valid
private List<FilterDefinition> filters = new ArrayList<>();
/**
* 路由向的 URI
*/
@NotNull
private URI uri;
/**
* 顺序
*/
private int order = 0;
}

  • id 属性,ID 编号,唯一
  • predicates 属性,谓语定义数组。请求通过 predicates 判断是否匹配。在 Route 里,PredicateDefinition 转换成 Predicate 。
  • filters 属性,过滤器定义数组。在 Route 里,FilterDefinition 转换成 GatewayFilter 。
  • uri 属性,路由向的 URI 。
  • order 属性,顺序。当请求匹配到多个路由时,使用顺序的。

RouteDefinition 提供 text 字符串创建对象,代码如下 :

/**
* 根据 text 创建 RouteDefinition
*
* @param text 格式 ${id}=${uri},${predicates[0]},${predicates[1]}...${predicates[n]}
* 例如 route001=http://127.0.0.1,Host=**.addrequestparameter.org,Path=/get
*/
public RouteDefinition(String text) {
int eqIdx = text.indexOf("=");
if (eqIdx <= 0) {
throw new ValidationException("Unable to parse RouteDefinition text '" + text + "'" +
", must be of the form name=value");
}
// id
setId(text.substring(0, eqIdx));
// predicates
String[] args = tokenizeToStringArray(text.substring(eqIdx+1), ",");
// uri
setUri(URI.create(args[0]));

for (int i=1; i < args.length; i++) {
this.predicates.add(new PredicateDefinition(args[i]));
}
}

  • text 参数,格式为 ${id}=${uri},${predicates[0]},${predicates[1]}...${predicates[n]} 。举个例子, "route001=http://127.0.0.1,Host=**.addrequestparameter.org,Path=/get" 。创建的 RouteDefinition 如下图 :
  • filters 属性,需要通过调用 RouteDefinition#setFilters(filters) 方法进行设置。
  • order 属性,需要通过调用 RouteDefinition#setOrder(order) 方法进行设置。
  • predicates 属性,支持解析,但是如果此处单个 PredicateDefinition 的 args[i] 存在逗号( , ) ,会被错误的分隔,例如说,"Query=foo,bz"

3. PredicateDefinition

org.springframework.cloud.gateway.handler.predicate.PredicateDefinition ,谓语定义。请求通过 predicates 判断是否匹配。代码如下 :

@Validated
public class PredicateDefinition {

/**
* 谓语定义名字
*/
@NotNull
private String name;
/**
* 参数数组
*/
private Map<String, String> args = new LinkedHashMap<>();
}

  • name 属性,谓语定义名字。通过 name 对应到 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory实现类。例如说,name=Query 对应到 QueryRoutePredicateFactory 。
  • args 属性,参数数组。例如,name=Host / args={"_genkey_0" : "iocoder.cn"} ,匹配请求的 hostnameiocoder.cn

PredicateDefinition 提供 text 字符串创建对象,代码如下 :

/**
* 根据 text 创建 PredicateDefinition
*
* @param text 格式 ${name}=${args[0]},${args[1]}...${args[n]}
* 例如 Host=iocoder.cn
*/
public PredicateDefinition(String text) {
int eqIdx = text.indexOf("=");
if (eqIdx <= 0) {
throw new ValidationException("Unable to parse PredicateDefinition text '" + text + "'" +
", must be of the form name=value");
}
// name
setName(text.substring(0, eqIdx));
// args
String[] args = tokenizeToStringArray(text.substring(eqIdx+1), ",");
for (int i=0; i < args.length; i++) {
this.args.put(NameUtils.generateName(i), args[i]);
}
}

  • text 参数,格式为 ${name}=${args[0]},${args[1]}...${args[n]} 。举个例子, "Host=iocoder.cn" 。创建的 PredicateDefinition 如下图 :

4. FilterDefinition

FilterDefinition 和 PredicateDefinition 的代码实现上基本一致

org.springframework.cloud.gateway.filter.FilterDefinition ,过滤器定义。代码如下 :

@Validated
public class FilterDefinition {

/**
* 过滤器定义名字
*/
@NotNull
private String name;
/**
* 参数数组
*/
private Map<String, String> args = new LinkedHashMap<>();
}

  • name 属性,过滤器定义名字。通过 name 对应到 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory实现类。例如说,name=AddRequestParameter 对应到 AddRequestParameterGatewayFilterFactory 。
  • args 属性,参数数组。例如,name=AddRequestParameter / args={"_genkey_0": "foo", "_genkey_1": "bar"} ,添加请求参数 foobar

FilterDefinition 提供 text 字符串创建对象,代码如下 :

/**
* 根据 text 创建 FilterDefinition
*
* @param text 格式 ${name}=${args[0]},${args[1]}...${args[n]}
* 例如 AddRequestParameter=foo, bar
*/
public FilterDefinition(String text) {
int eqIdx = text.indexOf("=");
if (eqIdx <= 0) {
setName(text);
return;
}
// name
setName(text.substring(0, eqIdx));
// args
String[] args = tokenizeToStringArray(text.substring(eqIdx+1), ",");
for (int i=0; i < args.length; i++) {
this.args.put(NameUtils.generateName(i), args[i]);
}
}

  • text 参数,格式为 ${name}=${args[0]},${args[1]}...${args[n]} 。举个例子, "AddRequestParameter=foo, bar" 。创建的 FilterDefinition 如下图 :

5. RouteDefinitionLocator

org.springframework.cloud.gateway.route.RouteDefinitionLocator ,路由定义定位器接口,定义获得路由定义数组的方法。代码如下 :

public interface RouteDefinitionLocator {

Flux<RouteDefinition> getRouteDefinitions();
}

  • 对 Reactor Flux 暂时不熟悉的同学,可以阅读完本文 Google 进行学习。随着 Spring 5 对响应式编程的推广,厉害如你一定要去掌握。

在上文中,我们也看到了 RouteDefinitionLocator 的多个实现类,类图如下 :

  • 本文只解析 CompositeRouteDefinitionLocator 的源码实现。其他的实现类会在后面文章详细解析。

6. CompositeRouteDefinitionLocator

org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。代码如下 :

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {

/**
* RouteDefinitionLocator 数组
*/
private final Flux<RouteDefinitionLocator> delegates;

public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
this.delegates = delegates;
}

@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
}

}

  • #getRouteDefinitions() 方法,提供统一方法,将组合的 delegates 的路由定义全部返回。

666. 彩蛋

知识星球

RouteDefinition => Route
PredicateDefinition => Predication
FilterDefinition => GatewayFilter

等等的转换,我们在后续路由相关的文章详细解析。

胖友,分享一波朋友圈可好!

文章目录
  1. 1. 1. 概述
  2. 2. 2. RouteDefinition
  3. 3. 3. PredicateDefinition
  4. 4. 4. FilterDefinition
  5. 5. 5. RouteDefinitionLocator
  6. 6. 6. CompositeRouteDefinitionLocator
  7. 7. 666. 彩蛋