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的原理基本完成,还有其他功能,与主流程无关,不过可以作为扩展适配个性化的需求。
本文转载自: 掘金