Spring Cloud Gateway Spring Cloud Gateway 路由功能详解
1. 生成路由的关键步骤
Spring Cloud Gateway 中路由的生成分为两个步骤:
- 根据 RouteDefinitonLocator 获取 RouteDefinition ;
- 根据 RouteLocator 获取 Route ;
其中 RouteDefinitionLocator 有两个实现, PropertiesRouteDefinitionLocator 和 RouteDefinitionRepository , PropertiesRouteDefinitionLocator 对应的是通过配置文件配置路由, RouteDefinitionRepository 对应的是通过仓储方式配置路由,比如 In-Memory 或 Redis 或 MySQL 等等。通过 RouteDefinitionRepository 仓储方式定义的路由我们称之为动态路由,我们可以在不影响现有路由的情况下动态添加路由或更新现有路由。
通过 RouteDefinitonLocator 生成的 RouteDefinition 最终要转换成 Route ,这一步通过 RouteDefinitionRouteLocator 来实现,其主要实现 RouteDefinition 到 Route 的转换工作。除此之外,我们还可以通过coding的方式直接定义 RouteLocator ,这需要借助 RouteLocatorBuilder.Builder#build 来实现。
下图是 spring-cloud-gateway 路由相关的核心类图,有没有一目了然的赶脚呢?
2. 路由配置示例
2.1 通过配置文件配置路由
spring:
cloud:
gateway:
routes:
- id: addUserCode
uri: http://localhost:8080/
filters:
- AddRequestHeader=userCode, Toman
predicates:
- Path=/demo/header
2.2 通过仓储配置路由
如果采用 NoSQL 或关系数据库存储则重写 getRouteDefinitions() 方法即可。
public class InMemoryRouteDefinitionRepository implements RouteDefinitionRepository {
private final Map<String, RouteDefinition> routes = synchronizedMap(
new LinkedHashMap<String, RouteDefinition>());
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(r -> {
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)));
});
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(routes.values());
}
}
2.3 通过 RouteLocatorBuilder 创建 RouteLocator
@Bean
RouteLocator requestHeader(RouteLocatorBuilder builder) {
return builder.routes().route(
predicateSpec -> predicateSpec.path("/demo/header")
.filters(filterSpec -> filterSpec.addRequestHeader("userCode", "Toman"))
.uri("http://localhost:8080").order(-1)
).build();
}
3. 路由的缓存处理
Spring Cloud Gateway获取路由的入口是 CachingRoteLocator.getRoutes() 。CahingRouteLocator负责路由的缓存工作,缓存是通过将路由信息存储到了本地map来实现的。
缓存信息的获取交由 CachingRouteLocator 的 delegator 来实现,delegator 是 CompositeRouteLocator ,它采用组合模式将所有的RouteLocator 实现组合到 delegators 内。
真正的 RouteLocator 实现有 RouteDefinitionRouteLocator 和通过 RouteLocatorBuilder#build 创建的 RouteLocator 对象。
4. 路由的刷新
通过动态路由更新路由配置信息后,通过spring事件机制发送 RefreshRoutesEvent 事件。 CachingRouteLocator 会监听该事件,在收到 RefreshRoutesEvent 事件后, 会清空缓存信息,待下次请求时重新加载路由信息并缓存。