Spring Cloud Gateway
| 框架 | 版本 |
|---|---|
| Spring Boot | 2.5.3 |
| Spring Cloud | 2020.0.3 |
maven依赖
1 | yaml复制代码 <dependency> |
概念
1 | scss复制代码路由(routes):gateway核心概念,包含了路由id、转发地址uri、一组断言、一组过滤器 |
实现方式
- 配置文件
1 | yaml复制代码spring: |
说明:
routes:路由集合,设定路由的id、转发url、断言、过滤器
id:需要唯一,用于存储和更新路由信息
uri:转发的地址
predicates:断言集合,多个断言类型取并集
filters:过滤器,多个过滤器都会执行
- java类
1 | java复制代码 @Bean |
说明:
RouteLocator:路由的主要对象,Gateway对于此对象的加载更新,可以实现动态路由
自定义断言
通过继承AbstractRoutePredicateFactory类可以快速实现一个自定义断言,需要自定义一个Config类用于接收断言内容,重写apply方法,返回一个GatewayPredicate类型.
1 | java复制代码@Configuration |
自定义过滤器:
1 | java复制代码@Configuration |
其中AbstractRoutePredicateFactory和AbstractGatewayFilterFactory是官方提供的静态实现类,其中实现了部分通用部分,只需要写自定义的apply方法即可,其中shortcutFieldOrder就是用来处理参数注入的。
原理解析
通过以上方式,我们可以快速实现一个基于Gateway的路由服务,那么生刨一下源码,来看下它是怎么实现的:
通过查看Spring-Cloud-Gateway的源码,查看其中的spring.factories可以知道主要的启动配置:
1 | properties复制代码# Auto Configure |
通过查看GatewayClassPathWarningAutoConfiguration,可以看出Gateway是基于WebFlux实现的
1 | java复制代码 @Configuration(proxyBeanMethods = false) |
关键点在于DispatcherServlet是基于Servlet实现的,当有这个Class加载的时候就会报错,当没有DispatcherHandler存在的时候就会报警告异常。
继续往下看GatewayAutoConfiguration就是我们要看的核心了,由于内容过多,只看其中比较重要的几个Bean加载:
1 | java复制代码 @Bean |
作为权重路由加载,因为WeightCalculatorWebFilter实现了WebFliter,而其他的路由是基于DispatcherHandler中的HandlerMapping实现的。
1 | java复制代码 @Bean |
RoutePredicateHandlerMapping就是整个路由的核心处理类,其实现了HandlerMapping接口,将会被注入到DispatcherHandler的handlerMappings中发挥作用。
查看RoutePredicateHandlerMapping中,核心方法如下:
1 | java复制代码 @Override |
此方法在DispatcherHandler的主方法中会调用,其中方法lookupRoute就会通过断言规则return r.getPredicate().apply(exchange),获取对应的Route返回,然后再后续的FilteringWebHandler中通过GATEWAY_ROUTE_ATTR属性获取Route对象,然后执行对象中的所有Filters。
1 | java复制代码 @Override |
前面的流程基本说明的整个Gateway的基础工作原理,而通过前面的逻辑,可以看到主要是通过RouteLocator类的getRoutes方法获取路由信息:
1 | java复制代码 |
其中核心代码:
1 | java复制代码 RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName()); |
也就是说是通过类名获取到对应的断言工厂的,而加载所有工厂的RoutePredicateFactory类中的方法:
1 | java复制代码default String name() { |
通过查看实现方法发现
1 | java复制代码return removeGarbage(clazz.getSimpleName().replace(RoutePredicateFactory.class.getSimpleName(), "")); |
也就是说,自己实现的RoutePredicateFactory要是以RoutePredicateFactory结尾的话,就能想PathRoutePredicateFactory那样在断言里面写Path=/**然后自动找到断言实现类,不然就要自己实现getSimpleName方法。
而通过路由的Filters中的信息加载GatewayFilterFactory也是类似的实现:
1 | java复制代码 |
GatewayFilterFactory:
1 | java复制代码default String name() { |
到此,基本整个Gateway的原理基本完成,还有其他功能,与主流程无关,不过可以作为扩展适配个性化的需求。
本文转载自: 掘金