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 事件后, 会清空缓存信息,待下次请求时重新加载路由信息并缓存。