【Spring Cloud】Gateway —— RouteLocator RouteDefinitionLocator FilteringWebHandler
前言
从 RouteLocator
RouteDefinitionLocator
FilteringWebHandler
及相关装配类的维度记录一下 Spring Cloud Gateway
RouteLocator
public interface RouteLocator {
Flux<Route> getRoutes();
}
路由(Route
)定位类,一般配置 Spring Cloud Gateway
我们也会基于 RouteLocatorBuilder
构造对应的 RouteLocator
,诸如:
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p
.path("/client1/{segment}")
.filters(f -> f.stripPrefix(1))
.uri("http://localhost:8801/")
)
.build();
}
当然,它是支持多组路由收集的:
CachingRouteLocator
缓存内部的 RouteLocator
并基于事件刷新
CompositeRouteLocator
组合,将多组 RouteLocator
组合成一个
RouteDefinitionRouteLocator
@Override
public Flux<Route> getRoutes() {
/**
* 基于 routeDefinitionLocator 获取所有 RouteDefinition
* 转换成 Route 实例
*/
Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);
// ...
return routes.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition matched: " + route.getId());
}
return route;
});
}
- 基于
routeDefinitionLocator
获取所有RouteDefinition
并转换成Route
实例 - 可以看到,真正负责路由解析的就只有此类,以及我们之前提到配置类中基于
RouteLocatorBuilder
构造的匿名实例
装配类 GatewayAutoConfiguration
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator, ConfigurationService configurationService) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, gatewayFilters, properties,
configurationService);
}
@Bean
@Primary
@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
/**
* 组合所有 RouteLocator 实例并缓存
*/
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
自动装配类 GatewayAutoConfiguration 中:
- 注册了
RouteDefinitionRouteLocator
实例 - 收集容器中所有
RouteLocator
实例(实际上就是我们上面描述的两种),Composite
并Caching
,注册CachingRouteLocator
实例 - 因为
@Primary
注解,因此之后容器中主要使用的就是cachedCompositeRouteLocator
这个实例了
RouteDefinitionLocator
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
- 之前提到,
RouteDefinitionRouteLocator
基于routeDefinitionLocator
获取所有RouteDefinition
并转换成Route
实例 RouteDefinitionLocator
,路由定义定位器,用于收集多组RouteDefinition
,最终交给RouteDefinitionRouteLocator
转换成Route
CachingRouteDefinitionLocator
缓存内部的 RouteDefinitionLocator
并基于事件刷新
CompositeRouteDefinitionLocator
它组合了一组 RouteDefinitionLocator
,因而 getRouteDefinitions
方法是发射所有的 RouteDefinition
元素
InMemoryRouteDefinitionRepository
基于内存管理一组 RouteDefinition
,提供了 save
delete
方法,自动装配类中默认提供了实例,可以自行覆盖,如下:
@Bean
public RouteDefinitionRepository repository() {
PredicateDefinition predicateDefinition = new PredicateDefinition("Path=/eureka-client/{segement}");
FilterDefinition filterDefinition = new FilterDefinition("StripPrefix=1");
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId("test-repo");
routeDefinition.setPredicates(Arrays.asList(new PredicateDefinition[] { predicateDefinition }));
routeDefinition.setFilters(Arrays.asList(new FilterDefinition[] { filterDefinition }));
routeDefinition.setUri(URI.create("http://localhost:8801"));
InMemoryRouteDefinitionRepository repository = new InMemoryRouteDefinitionRepository();
Mono<RouteDefinition> route = Mono.fromSupplier(() -> routeDefinition);
// 这里必须 subscribe 一下,暂不知原因 @TODO
repository.save(route).subscribe();
return repository;
}
PropertiesRouteDefinitionLocator
private final GatewayProperties properties;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(this.properties.getRoutes());
}
基于 GatewayProperties
获取,实际上就是基于 配置文件
读取,类似:
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: test
uri: http://localhost:8801
predicates:
- Path=/client/{segement}
filters:
- StripPrefix=1
DiscoveryClientRouteDefinitionLocator
这个类是基于 服务发现
来为每个服务生成默认的 RouteDefinition
,基于 PathRoutePredicateFactory
匹配路由,基于 RewritePathGatewayFilterFactory
重写路径为 lb://
+ serviceId
装配类
GatewayAutoConfiguration
@Bean
@ConditionalOnMissingBean
public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
return new PropertiesRouteDefinitionLocator(properties);
}
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
return new InMemoryRouteDefinitionRepository();
}
@Bean
@Primary
public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
}
- 注册基于配置文件解析的
PropertiesRouteDefinitionLocator
- 注册基于内存管理的
InMemoryRouteDefinitionRepository
CompositeRouteDefinitionLocator
管理上述所有RouteDefinitionLocator
,标注@Primary
,容器中可以直接注入使用
GatewayDiscoveryClientAutoConfiguration
@Bean
public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
properties.setPredicates(initPredicates());
properties.setFilters(initFilters());
return properties;
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.discovery.reactive.enabled", matchIfMissing = true)
public static class ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}
}
- 配置服务发现默认的路由匹配器和过滤器,即之前提到的
PathRoutePredicateFactory
和RewritePathGatewayFilterFactory
- 注册
DiscoveryClientRouteDefinitionLocator
实例,基于配置项spring.cloud.gateway.discovery.locator.enabled=true
FilteringWebHandler
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
/**
* 从 route 实例中获取拦截器,此处包括 default-filters
*/
List<GatewayFilter> gatewayFilters = route.getFilters();
/**
* 再加入 globalFilters
*/
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
// 基于 Order 接口排序
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
// 拦截操作
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
- 此处会获取
Route
实例中的所有Filter
,包括default-filters
(配置文件指定,配置项spring.cloud.gateway.default-filters
) - 还会加上所有容器中的
globalFilters
,装配类中默认注册了不少,略 - 最后进行拦截操作
装配类 GatewayAutoConfiguration
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}
总结
Spring Cloud Gateway
源码阅读的相关记录