基本組件
路由定位器(RouteDefinitionLocator )
RouteDefinitionLocator 負責讀取路由配置(RouteDefinition
),Gateway實現了多種Locator。
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
- PropertiesRouteDefinitionLocator
從配置文件( 例如,YML / Properties 等 ) 讀取
- RouteDefinitionRepository
從存儲器( 例如,內存 / Redis / MySQL 等 )讀取。
- DiscoveryClientRouteDefinitionLocator
從註冊中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )讀取。
- CompositeRouteDefinitionLocator
組合多種 RouteDefinitionLocator 的實現,爲 RouteDefinitionRouteLocator 提供統一入口。
- CachingRouteDefinitionLocator
已經被 CachingRouteLocator 取代。
路由定義(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<>();
@NotNull
private URI uri;
private int order = 0;
}
id
屬性,ID 編號,唯一。predicates
屬性,謂語定義數組。請求通過predicates
判斷是否匹配。在 Route 裏,PredicateDefinition 轉換成 Predicate 。filters
屬性,過濾器定義數組。在 Route 裏,FilterDefinition 轉換成 GatewayFilter 。uri
屬性,路由向的 URI 。order
屬性,順序。當請求匹配到多個路由時,使用順序小的。
RouteDefinition 提供 text
字符串創建對象(yaml配置中屬性值),格式爲:
${id}=${uri},${predicates[0]},${predicates[1]}...${predicates[n]}
public RouteDefinition(String text) ;
PredicateDefinition
@Validated
public class PredicateDefinition {
/**
* 謂語定義名字,通過 name 對應到 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 的實現類
*/
@NotNull
private String name;
/**
* 參數數組
*/
private Map<String, String> args = new LinkedHashMap<>();
}
提供了構造函數:
/**
* 根據 text 創建 PredicateDefinition
*
* @param text 格式 ${name}=${args[0]},${args[1]}...${args[n]}
* 例如 Host=iocoder.cn
*/
public PredicateDefinition(String text);
FilterDefinition
@Validated
public class FilterDefinition {
/**
* 過濾器定義名字。通過 name 對應到 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 的實現類
*/
@NotNull
private String name;
/**
* 參數數組
*/
private Map<String, String> args = new LinkedHashMap<>();
}
提供了構造函數:
/**
* 根據 text 創建 FilterDefinition
*
* @param text 格式 ${name}=${args[0]},${args[1]}...${args[n]}
* 例如 AddRequestParameter=foo, bar
*/
public FilterDefinition(String text);
CompositeRouteDefinitionLocator
組合多種 RouteDefinitionLocator 的實現,爲 RouteDefinitionRouteLocator 提供統一入口
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions)
.flatMap(routeDefinition -> {
if (routeDefinition.getId() == null) {
return randomId().map(id -> {
routeDefinition.setId(id);
if (log.isDebugEnabled()) {
log.debug(
"Id set on route definition: " + routeDefinition);
}
return routeDefinition;
});
}
return Mono.just(routeDefinition);
});
}
路由定位器 (RouteLocator)
- RouteLocator 可以直接自定義路由(
org.springframework.cloud.gateway.route.Route
) ,也可以通過 RouteDefinitionRouteLocator 獲取 RouteDefinition ,並轉換成 Route 。 - RoutePredicateHandlerMapping 使用 RouteLocator 獲得 Route 信息。
Route
Route與RouteDefinition結構相似。同時實現了Order接口。
public class Route implements Ordered {
/**
* 路由編號
*/
private final String id;
/**
* 路由向的 URI
*/
private final URI uri;
/**
* 順序
*/
private final int order;
/**
* 謂語數組
*/
private final Predicate<ServerWebExchange> predicate;
/**
* 過濾器數組
*/
private final List<GatewayFilter> gatewayFilters;
}
Route 內置 Builder 類,根據RouteDefinition 構造對象。predicate
/ gatewayFilters
屬性,需要調用 Builder 相關方法進行設置
public static Builder builder(RouteDefinition routeDefinition) {
// @formatter:off
return new Builder().id(routeDefinition.getId())
.uri(routeDefinition.getUri())
.order(routeDefinition.getOrder())
.metadata(routeDefinition.getMetadata());
// @formatter:on
}
RouteDefinitionLocator解析
PropertiesRouteDefinitionLocator
從GatewayProperties 中獲取路由信息。
public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
private final GatewayProperties properties;
public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
this.properties = properties;
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(this.properties.getRoutes());
}
}
GatewayProperties
GatewayProperties
,從配置文件讀取 :
- 路由配置
通過 spring.cloud.gateway.routes
配置
- 默認過濾器配置。當 RouteDefinition => Route 時,會將過濾器配置添加到每個 Route 。
通過 spring.cloud.gateway.default-filters
配置
@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
/**
* List of Routes.
*/
@NotNull
@Valid
private List<RouteDefinition> routes = new ArrayList<>();
/**
* List of filter definitions that are applied to every route.
*/
private List<FilterDefinition> defaultFilters = new ArrayList<>();
}
RouteDefinitionRepository
public interface RouteDefinitionRepository
extends RouteDefinitionLocator, RouteDefinitionWriter {
}
類繼承關係如下:
RouteDefinitionWriter
RouteDefinitionWriter
,路由配置寫入接口。該接口定義了保存與刪除兩個方法
public interface RouteDefinitionWriter {
/**
* 保存路由配置
*
* @param route 路由配置
* @return Mono<Void>
*/
Mono<Void> save(Mono<RouteDefinition> route);
/**
* 刪除路由配置
*
* @param routeId 路由編號
* @return Mono<Void>
*/
Mono<Void> delete(Mono<String> routeId);
}
InMemoryRouteDefinitionRepository
基於內存爲存儲器的 RouteDefinitionLocator
public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository {
private final Map<String, RouteDefinition> routes = synchronizedMap(
new LinkedHashMap<String, RouteDefinition>());
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(routes.values());
}
}
路由信息構造:
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(r -> {
if (StringUtils.isEmpty(r.getId())) {
return Mono.error(new IllegalArgumentException("id may not be empty"));
}
routes.put(r.getId(), r);
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
if (routes.containsKey(id)) {
routes.remove(id);
return Mono.empty();
}
return Mono.defer(() -> Mono.error(
new NotFoundException("RouteDefinition not found: " + routeId)));
});
}
自定義RouteDefinitionRepository
可以自定義RouteDefinitionRepository,如果沒有自定義,才使用內存存儲。
// GatewayAutoConfiguration.java
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
return new InMemoryRouteDefinitionRepository();
}
DiscoveryClientRouteDefinitionLocator
DiscoveryClientRouteDefinitionLocator 通過調用 org.springframework.cloud.client.discovery.DiscoveryClient
獲取註冊在註冊中心的服務列表,生成對應的 RouteDefinition 數組。
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
private final DiscoveryLocatorProperties properties;
private final String routeIdPrefix;
private final SimpleEvaluationContext evalCtxt;
private Flux<List<ServiceInstance>> serviceInstances;
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression includeExpr = parser
.parseExpression(properties.getIncludeExpression());
Expression urlExpr = parser.parseExpression(properties.getUrlExpression());
//構造服務實例是否可用predicate。
Predicate<ServiceInstance> includePredicate;
if (properties.getIncludeExpression() == null
|| "true".equalsIgnoreCase(properties.getIncludeExpression())) {
includePredicate = instance -> true;
}
else {
includePredicate = instance -> {
Boolean include = includeExpr.getValue(evalCtxt, instance, Boolean.class);
if (include == null) {
return false;
}
return include;
};
}
return serviceInstances.filter(instances -> !instances.isEmpty())
//返回可用實例
.map(instances -> instances.get(0)).filter(includePredicate)
.map(instance -> {
//構建definition
RouteDefinition routeDefinition = buildRouteDefinition(urlExpr,
instance);
final ServiceInstance instanceForEval = new DelegatingServiceInstance(
instance, properties);
//拷貝PredicateDefinition
for (PredicateDefinition original : this.properties.getPredicates()) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs()
.entrySet()) {
//計算表達式值。
String value = getValueFromExpr(evalCtxt, parser,
instanceForEval, entry);
predicate.addArg(entry.getKey(), value);
}
routeDefinition.getPredicates().add(predicate);
}
//拷貝FilterDefinition
for (FilterDefinition original : this.properties.getFilters()) {
FilterDefinition filter = new FilterDefinition();
filter.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs()
.entrySet()) {
//計算表達式值。
String value = getValueFromExpr(evalCtxt, parser,
instanceForEval, entry);
filter.addArg(entry.getKey(), value);
}
routeDefinition.getFilters().add(filter);
}
return routeDefinition;
});
}
RouteLocator解析
RouteLocator
路由定位器接口,定義獲得路由數組的方法
public interface RouteLocator {
Flux<Route> getRoutes();
}
CompositeRouteLocator
組合多種 RouteLocator 的實現類,爲 RoutePredicateHandlerMapping 提供統一入口訪問路由
public class CompositeRouteLocator implements RouteLocator {
private final Flux<RouteLocator> delegates;
public CompositeRouteLocator(Flux<RouteLocator> delegates) {
this.delegates = delegates;
}
@Override
public Flux<Route> getRoutes() {
return this.delegates.flatMap(RouteLocator::getRoutes);
}
}
CachingRouteLocator
CachingRouteLocator
,緩存路由的 RouteLocator 實現類。RoutePredicateHandlerMapping 調用 CachingRouteLocator 的 RouteLocator#getRoutes()
方法,獲取路由。
public class CachingRouteLocator
implements Ordered, RouteLocator, ApplicationListener<RefreshRoutesEvent> {
private static final String CACHE_KEY = "routes";
private final RouteLocator delegate;
private final Flux<Route> routes;
private final Map<String, List> cache = new ConcurrentHashMap<>();
public CachingRouteLocator(RouteLocator delegate) {
this.delegate = delegate;
routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
.onCacheMissResume(this::fetch);
}
}
RouteDefinitionRouteLocator
RouteDefinitionRouteLocator
,基於 RouteDefinitionLocator 的 RouteLocator 實現類。RouteDefinitionRouteLocator 從 RouteDefinitionLocator 獲取 RouteDefinition ,轉換成 Route
public class RouteDefinitionRouteLocator
implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
/**
* Default filters name.
*/
public static final String DEFAULT_FILTERS = "defaultFilters";
protected final Log logger = LogFactory.getLog(getClass());
private final RouteDefinitionLocator routeDefinitionLocator;
private final ConfigurationService configurationService;
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
private final GatewayProperties gatewayProperties;
}
構造函數
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RoutePredicateFactory> predicates,
List<GatewayFilterFactory> gatewayFilterFactories,
GatewayProperties gatewayProperties,
ConfigurationService configurationService) {
this.routeDefinitionLocator = routeDefinitionLocator;
this.configurationService = configurationService;
initFactories(predicates);
gatewayFilterFactories.forEach(
factory -> this.gatewayFilterFactories.put(factory.name(), factory));
this.gatewayProperties = gatewayProperties;
}
獲得 Route
@Override
public Flux<Route> getRoutes() {
//routeDefinitionLocator獲取RouteDefinitions,轉換成Route
Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
.map(this::convertToRoute);
//錯誤是否拋出異常
if (!gatewayProperties.isFailOnRouteDefinitionError()) {
// instead of letting error bubble up, continue
routes = routes.onErrorContinue((error, obj) -> {
if (logger.isWarnEnabled()) {
logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
+ " will be ignored. Definition has invalid configs, "
+ error.getMessage());
}
});
}
return routes.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition matched: " + route.getId());
}
return route;
});
}
//合併predicate,合併filters,構造一個route。
private Route convertToRoute(RouteDefinition routeDefinition) {
AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
return Route.async(routeDefinition).asyncPredicate(predicate)
.replaceFilters(gatewayFilters).build();
}
自定義 RouteLocator
RouteLocatorBuilder用於自定義RouteLocator
public class RouteLocatorBuilder {
public Builder routes() {
return new Builder(context);
}
}
public static class Builder {
private List<Route.AsyncBuilder> routes = new ArrayList<>();
private ConfigurableApplicationContext context;
public Builder(ConfigurableApplicationContext context) {
this.context = context;
}
}
- RouteSpec:route builder。
- UriSpec:可以添加一個Uri
- PredicateSpec:可以應用到一個Uri的Predicate。
- BooleanOpSpec:邏輯操作Predicate。
- GatewayFilterSpec:GatewayFilter