SpringCloudGateway小记
目录标题
GateWayProperties
public class GatewayProperties {
/**
* List of Routes.
*/
private List<RouteDefinition> routes = new ArrayList<>();
/**
* List of filter definitions that are applied to every route.
*/
private List<FilterDefinition> defaultFilters = new ArrayList<>();
private List<MediaType> streamingMediaTypes = Arrays
.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON);
对应配置文件中:
spring:
cloud:
gateway:
default-filters:
- PrefixPath=/httpbin
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
routes:
- id: websocket_test
uri: ws://localhost:9000
order: 9000
predicates:
- Path=/echo
# =====================================
- id: default_path_to_httpbin
uri: ${test.uri}
order: 10000
predicates:
- Path=/**
List<FilterDefinition> defaultFilters
org.springframework.cloud.gateway.filter.FilterDefinition
public class FilterDefinition {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
public FilterDefinition(String text) {
int eqIdx = text.indexOf('=');
if (eqIdx <= 0) {
setName(text);
return;
}
setName(text.substring(0, eqIdx));
String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
for (int i = 0; i < args.length; i++) {
this.args.put(NameUtils.generateName(i), args[i]);
}
}
-------------
public final class NameUtils {
/**
* Generated name prefix.
*/
public static final String GENERATED_NAME_PREFIX = "_genkey_";
public static String generateName(int i) {
return GENERATED_NAME_PREFIX + i;
}
配置DEMO
spring:
cloud:
gateway:
default-filters:
- PrefixPath=/httpbin
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
构造函数 参数只有一个字符串
name=value1,value2,value3,…
故每个FilterDefinition 的name与args 的Value 为外部配置,args 的Key 为自动生成 规则为 _genkey_+序号
List routes
org.springframework.cloud.gateway.route.RouteDefinition
public class RouteDefinition {
private String id;
private List<PredicateDefinition> predicates = new ArrayList<>();
private List<FilterDefinition> filters = new ArrayList<>();
private URI uri;
private Map<String, Object> metadata = new HashMap<>();
private int order = 0;
public RouteDefinition() {
}
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");
}
setId(text.substring(0, eqIdx));
String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
setUri(URI.create(args[0]));
for (int i = 1; i < args.length; i++) {
this.predicates.add(new PredicateDefinition(args[i]));
}
}
配置DEMO
spring:
cloud:
gateway:
routes:
- id: websocket_test
uri: ws://localhost:9000
order: 9000
predicates:
- Path=/echo
# =====================================
- id: default_path_to_httpbin
uri: ${test.uri}
order: 10000
predicates:
- Path=/**
List predicates
配置匹配表达式
public class PredicateDefinition {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
public PredicateDefinition() {
}
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");
}
setName(text.substring(0, eqIdx));
String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
for (int i = 0; i < args.length; i++) {
this.args.put(NameUtils.generateName(i), args[i]);
}
}
构造函数 参数只有一个字符串
name=value1,value2,value3,…
故每个PredicateDefinition 的name与args 的Value 为外部配置,args 的Key 为自动生成 规则为 _genkey_+序号
Route
org.springframework.cloud.gateway.route.Route
路由的基础单位
业务代码:
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute
public class Route implements Ordered {
private final String id;
private final URI uri;
private final int order;
/**
* 本路由的匹配规则
*/
private final AsyncPredicate<ServerWebExchange> predicate;
/**
* 需要执行的过滤器
*/
private final List<GatewayFilter> gatewayFilters;
private final Map<String, Object> metadata;
路由工厂
org.springframework.cloud.gateway.route.RouteLocator
/**
* @author Spencer Gibb
*/
// TODO: rename to Routes?
public interface RouteLocator {
Flux<Route> getRoutes();
}
默认的 SpringCloudGateWay 的 路由工厂使用
org.springframework.cloud.gateway.route.CachingRouteLocator
CachingRouteLocator 实现
org.springframework.cloud.gateway.config.GatewayAutoConfiguration#cachedCompositeRouteLocator
public CachingRouteLocator(RouteLocator delegate) {
this.delegate = delegate;
routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
.onCacheMissResume(this::fetch);
}
才用组合委托设计实现
基础 RouteLocator 定义
Bean 定义模式
@Bean
open fun additionalRouteLocator(builder: RouteLocatorBuilder) = builder.routes {
route(id = "test-kotlin") {
host("kotlin.abc.org") and path("/image/png")
filters {
prefixPath("/httpbin")
addResponseHeader("X-TestHeader", "foobar")
}
uri(uri)
}
}
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("circuitbreaker_route", r -> r.path("/consumingServiceEndpoint")
.filters(f -> f.circuitBreaker(c -> c.name("myCircuitBreaker").fallbackUri("forward:/inCaseOfFailureUseThis").addStatusCode("INTERNAL_SERVER_ERROR"))
.rewritePath("/consumingServiceEndpoint", "/backingServiceEndpoint")).uri("lb://backing-service:8088")
.build();
}
使用YAML 配置文件
spring:
cloud:
gateway:
default-filters:
- PrefixPath=/
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
routes:
- id: websocket_test
uri: ws://localhost:9000
order: 9000
predicates:
- Path=/echo
配置文件读取上GateWayProperties
配置文件实例化 RouteLocator
RouteDefinition 定义 RouteLocator
public List<RouteDefinition> getRoutes() {
return routes;
}
org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator
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());
}
}
在此加载 RouteLocator 的定义文件 (RouteDefinition)
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getRoutes
@Override
public Flux<Route> getRoutes() {
Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
.map(this::convertToRoute);
private Route convertToRoute(RouteDefinition routeDefinition) {
AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
return Route.async(routeDefinition).asyncPredicate(predicate)
.replaceFilters(gatewayFilters).build();
}
RouteDefinition 转换为 Router
Gateway 总路由
GateWay 映射
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}
路由转发与过滤器
org.springframework.web.reactive.DispatcherHandler#handle
使用SpringWebFlux
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
下一篇: 正则表达试!100分等带