Spring-Cloud-Gateway-路由定位器RouteLocator源码解析
前言
在整理和优化 星云网关 的时候,顺便仔细看了看Spring Cloud Gateway源码
网关代码
1 |
|
因为此篇博客关注点在于源码解析,所以网关的具体代码实现先不讲。
网关代码和Spring Cloud Gateway的关系
DynamicRouteDefinitionLocator实现了RouteDefinitionLocator接口- 通过 getRouteDefinitions() 方法向Spring Cloud Gateway提供路由配置
引起的思考
我们自定义的DynamicRouteDefinitionLocator类,它实现了RouteDefinitionLocator接口,那么自定义类是如何与Spring Cloud Gateway的核心路由加载机制相结合的呢。
源码解析
先说结论:整个路由加载的链路可以表示如下:
1 | 请求匹配/路由刷新事件 |
关键链路源码分析
CachingRouteLocator
CachingRouteLocator是路由请求的入口点,它实现了缓存机制以提升性能。
外部调用getRoutes()方法,从而构造函数执行。
getRoutes()方法
1 |
|
构造函数
1 | public CachingRouteLocator(RouteLocator delegate) { |
CacheFlux.lookup():在cache 中查找键为 CACHE_KEY (“routes”) 的路由数据,当缓存中不存在数据时,通过onCacheMissResume触发fetch()方法。
并且它是懒加载,构造时不立刻加载数据,首次访问时从 delegate 获取数据并缓存,后续访问直接从缓存返回。
它接受一个
RouteLocator类型的delegate参数同时我们可以在GatewayAutoConfiguration,这个delegate实际上是
CompositeRouteLocator实例。1
2
3
4
5
6
7
8
// TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
fetch() 方法
调用delegate.getRoutes()来获取路由,即委托给CompositeRouteLocator。
1 | private Flux<Route> fetch() { |
CompositeRouteLocator
CompositeRouteLocator负责聚合多个RouteLocator实例,提供一个统一的路由流。
构造函数
接受一个Flux<RouteLocator>类型的delegates参数,该参数包含了所有具体的RouteLocatorBean(如RouteDefinitionRouteLocator)
1 | public CompositeRouteLocator(Flux<RouteLocator> delegates) { |
getRoutes() 方法
1 |
|
使用flatMapSequential顺序调用每个delegate的getRoutes()方法,并将结果合并成一个统一的Flux<Route>
也就是说,当CachingRouteLocator调用delegate.getRoutes()时,实际是调用CompositeRouteLocator.getRoutes(),后者再调用所有注册的RouteLocator的getRoutes()方法
RouteDefinitionRouteLocator
RouteDefinitionRouteLocator是具体的路由定位器,负责将路由定义(RouteDefinition)转换为可用的Route对象
getRoutes() 方法
1 |
|
从routeDefinitionLocator获取RouteDefinition流,并通过convertToRoute方法将每个定义转换为Route
convertToRoute 方法
组合断言(predicates)和过滤器(filters),构建完整的Route对象
1 | private Route convertToRoute(RouteDefinition routeDefinition) { |
因此,当CompositeRouteLocator调用其delegates时,RouteDefinitionRouteLocator会生成实际的路由规则,这些规则被聚合到CompositeRouteLocator的返回流中
RouteDefinitionLocator接口调用
RouteDefinitionRouteLocator的getRoutes()方法里执行了this.routeDefinitionLocator.getRouteDefinitions()
也就是RouteDefinitionLocator的getRouteDefinitions()方法
CompositeRouteDefinitionLocator
作为RouteDefinitionLocator接口的实现类,执行了getRouteDefinitions方法
1 | public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator { |
- delegates: 包含了所有注册的 RouteDefinitionLocator 实现
- flatMapSequential(RouteDefinitionLocator::getRouteDefinitions): 对集合中的每个定位器调用其 getRouteDefinitions() 方法
- 我们的DynamicRouteDefinitionLocator: 作为其中一个 RouteDefinitionLocator 实例被包含在 delegates 集合中
DynamicRouteDefinitionLocator
终于到了我们自己定义的动态路由定义定位器
- 我们的 DynamicRouteDefinitionLocator 被标记为 @Component 并注册为Spring Bean
- Spring容器自动将其注入到 CompositeRouteDefinitionLocator 的 delegates 集合中
- 因此在 flatMapSequential 操作中会遍历到你的实例并调用其 getRouteDefinitions() 方法
RedisRouteDefinitionRepository
将存储逻辑分离到 RedisRouteDefinitionRepository,从Redis中获取路由定义。
由于篇幅有限 路由配置存储与加载 有关的内容,放于其他篇章介绍
总结
我们的DynamicRouteDefinitionLocator会被调用,它集成到了Spring Cloud Gateway的路由加载链路中。当网关需要路由定义时,会通过 CompositeRouteDefinitionLocator调用到您的实现,从而从Redis获取动态路由配置。
