點選上方“芋道原始碼”,選擇“置頂公眾號”
技術文章第一時間送達!
原始碼精品專欄
本文主要基於 Spring-Cloud-Gateway 2.0.X M4
-
1. 概述
-
2. RouteDefinition
-
3. PredicateDefinition
-
4. FilterDefinition
-
5. RouteDefinitionLocator
-
6. CompositeRouteDefinitionLocator
-
666. 彩蛋
1. 概述
本文主要對 路由定義定位器 RouteDefinitionLocator 做整體的認識。
在 《Spring-Cloud-Gateway 原始碼解析 —— 閘道器初始化》 中,我們看到路由相關的元件 RouteDefinitionLocator / RouteLocator 的初始化。涉及到的類比較多,我們用下圖重新梳理下 :
-
RouteDefinitionLocator 負責讀取路由配置(
org.springframework.cloud.gateway.route.RouteDefinition
) 。從上圖中我們可以看到,RouteDefinitionLocator 介面有四種實現 : -
PropertiesRouteDefinitionLocator ,從配置檔案( 例如,YML / Properties 等 ) 讀取。在 《Spring-Cloud-Gateway 原始碼解析 —— 路由(1.2)之 PropertiesRouteDefinitionLocator 配置檔案》「2. PropertiesRouteDefinitionLocator」 詳細解析。
-
RouteDefinitionRepository ,從儲存器( 例如,記憶體 / Redis / MySQL 等 )讀取。在 《Spring-Cloud-Gateway 原始碼解析 —— 路由(1.3)之 RouteDefinitionRepository 儲存器》 詳細解析。
-
DiscoveryClientRouteDefinitionLocator ,從註冊中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )讀取。在 《Spring-Cloud-Gateway 原始碼解析 —— 路由(1.4)之 DiscoveryClientRouteDefinitionLocator 註冊中心》 詳細解析。
-
CompositeRouteDefinitionLocator ,組合多種 RouteDefinitionLocator 的實現,為 RouteDefinitionRouteLocator 提供統一入口。在 本文 詳細解析。
-
另外,CachingRouteDefinitionLocator 也是 RouteDefinitionLocator 的實現類,已經被 CachingRouteLocator 取代。
-
RouteLocator 可以直接自定義路由(
org.springframework.cloud.gateway.route.Route
) ,也可以透過 RouteDefinitionRouteLocator 獲取 RouteDefinition ,並轉換成 Route 。 -
重要,對於上層呼叫者 RoutePredicateHandlerMapping ,使用的是 RouteLocator 和 Route 。而 RouteDefinitionLocator 和 RouteDefinition 用於透過配置定義路由。那麼自定義 RouteLocator 呢?透過程式碼定義路由。
推薦 Spring Cloud 書籍:
-
請支援正版。下載盜版,等於主動編寫低階 BUG 。
-
程式猿DD —— 《Spring Cloud微服務實戰》
-
周立 —— 《Spring Cloud與Docker微服務架構實戰》
-
兩書齊買,京東包郵。
推薦 Spring Cloud 影片:
-
Java 微服務實踐 – Spring Boot
-
Java 微服務實踐 – Spring Cloud
-
Java 微服務實踐 – Spring Boot / 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 predicates = new ArrayList<>();
/**
* 過濾器定義陣列
*/
@Valid
private List 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 args = new LinkedHashMap<>();
}
-
name
屬性,謂語定義名字。透過name
對應到org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory
的實現類。例如說,name=Query
對應到 QueryRoutePredicateFactory 。 -
args
屬性,引數陣列。例如,name=Host
/args={"_genkey_0" : "iocoder.cn"}
,匹配請求的hostname
為iocoder.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 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"}
,新增請求引數foo
為bar
。
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 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 delegates;
public CompositeRouteDefinitionLocator(Flux delegates) {
this.delegates = delegates;
}
@Override
public Flux getRouteDefinitions() {
return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
}
}
-
#getRouteDefinitions()
方法,提供統一方法,將組合的delegates
的路由定義全部傳回。
666. 彩蛋
RouteDefinition => Route
PredicateDefinition => Predication
FilterDefinition => GatewayFilter
等等的轉換,我們在後續路由相關的文章詳細解析。
胖友,分享一波朋友圈可好!