作者 | 波哥
审校 | 重楼
Spring Cloud Gateway是一个基于Spring Framework 5和Project Reactor的响应式API网关,旨在为构建分布式微服务架构提供高性能和灵活的路由机制。底层实现基于Spring WebFlux框架,它使用WebFlux的HandlerMapping和HandlerAdapter来处理请求和生成响应;使用了反应式编程的思想,基于Project Reactor库实现异步、非阻塞的事件驱动架构,以提高性能和吞吐量。
本文将带你深入spring Cloud Gateway的底层实现原理,重点关注其核心组件和代码实现。
1. Spring Cloud Gateway核心组件
Spring Cloud Gateway的核心组件主要有:
- Routes(路由):定义了URI、谓词(Predicates)和过滤器(Filters)的规则,用于将请求映射到后端服务。
- Predicates(谓词):定义了匹配条件,用于决定请求是否应该映射到该路由。
- Filters(过滤器):用于在请求和响应期间对请求和响应进行修改或转换。在调用过程中,会有多个过滤器形成过滤器链,用于处理请求、修改请求头、记录日志、限流等操作。
2.SpringCloud Gateway的具体使用
先来了解下Spring Cloud Gateway的具体使用过程,包括定义路由规则、自定义过滤器、启动应用等步骤。让我们逐步详细介绍这些步骤。
- 定义路由规则
首先,在Spring Cloud Gateway中,我们需要定义路由规则。路由规则定义了请求该如何被路由到后端服务。这些规则通常以Java或YAML配置文件的形式提供,以YAML配置为例:
- 自定义过滤器
我们可以编写自定义过滤器,对请求或响应进行特定的处理,例如添加头信息、修改请求、记录日志等。这里定义了要给GlobalFilter类型的过滤器,当然也可以定义非GlobalFilter类型的过滤器。
- 启动应用
通过启动Spring Boot应用程序,Spring Cloud Gateway将开始监听配置的端口,并根据路由规则将请求转发到相应的后端服务。
- 访问API
现在您可以通过访问定义的路由规则来测试API。
例如,对于上述路由规则的Java配置方式,可以使用以下URL访问API:
http://localhost:8080/sample/some-endpoint
Spring Cloud Gateway将根据路由规则将请求转发到http://example.com。
3.代码原理剖析
接下来,我们从上述使用案例入手,从GateWay的源码层面分析其底层实现原理。要理解其原理,其实只要理解如下这张图就足够了,所以接下来的分析我们将围绕这张图展开讲解。
Gateway作为网关,也就是统一的入口,它本身也是一个Web应用,在上面我们说过它是WebFlux框架,WebFlux大部分朋友可能都没接触过,我们可以使用SpringMVC进行类比。从上图我们可以看出,当请求到达Gateway后,首先会进入DispatcherHandler.handle方法进行处理,在该方法中调用GatewayHandlerMapping.getHandler方法,然后进入GatewayWebHandler.handle方法,随后进入Filter链进行处理,处理完成后调用具体的服务。综上,在整个的调用过程中使用到:DispatcherHandler、RoutePredicateHandlerMapping、SimpleHandlerAdapter、FilteringWebHandler几个核心的类(当然还使用到了Ribbon负载均衡、Netty/Nacos等注册中心相关的核心代码,不过本篇我们只分析Gateway相关源码),接下来我们将详细分析关键代码。
1.DispatcherHandler
该类做为Gateway的入口,接受所有网关的请求,类似于SpringMVC的DispatcherServlet类,所有的请求都将进入到handle方法中:
2.RoutePredicateHandlerMapping
这个RoutePredicateHandlerMapping就是上述handlerMappings的具体实现类,在handle方法就会使用到该类的实例,该类的主要作用是获取Route,也就是我们在配置文件中可能会配置多个Route,对于当前请求最终会使用哪个Route。
很多朋友会问:HandlerMappings有那么多实现类,你怎么知道会使用RoutePredicateHandlerMapping呢?
要回答这个问题,得对SpringBoot的底层实现有一定的了解,针对SpringBoot的底层实现大家可以看相关的文章,这里不做分析,在这里大家只需要寻找到
的spring.factories文件,SpringBoot会读取该文件中的配置,并将这些配置交由Spring容器管理就可以了。
在该配置中有一个配置类:GatewayAutoConfiguration,该配置类中完成对RoutePredicateHandlerMapping、FilteringWebHandler等的配置:
RoutePredicateHandlerMapping做为HandlerMapping的实现类,自然就会被调用到。
接下来我们看RoutePredicateHandlerMapping是如何帮我们寻找到Route的:
如上图代码所示,就是在lookupRoute方法中通过调用routeLocator.getRoutes方法获取到所有我们在应用配置文件中配置的Route(具体如何获取所有的Route源码比较简单,就是读取配置文件中的所有Route配置信息,这个大家可以自行去看下代码),然后调用getPredicate().apply方法确定具体的Route(也就是匹配断言),匹配成功后,会将该Route设置到exchange(可以理解为当前请求,即Request)的属性中:
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
3.SimpleHandlerAdapter
上述获取到Route后,接下来会进入到DispatcherHandler.invokeHandler方法:
该方法会执行SimpleHandlerAdapter的handle方法:
该方法调用WebHandler.handle方法,也就是FilteringWebHandler。
4.FilteringWebHandler
进入FilteringWebHandler.handle方法后,会从exchange上下文中得到Route,一个Route中可能有多个GatewayFilter,这里将多个GatewayFilter生成一个DefaultGatewayFilterChain链对象,然后启动链调用,这过程中会完成一些列的动作,比如整合Ribbon负载均衡获取到服务实例(ServerInstantce),最终调用NettyRoutingFilter完成对服务的调用。如下是Spring Cloud Gateway框架内置的GlobalFilter:
全局过滤器 |
作用 |
Forward Routing Filter |
用于本地forward,也就是将请求在Gateway服务内进行转发,而不是转发到下游服务 |
LoadBalancerClient Filter |
整合Ribbon实现负载均衡,得到最终的ServerInstance |
Netty Routing Filter |
使用Netty的HttpClient转发http、https请求 |
Netty Write Response Filter |
将代理响应写回网关的客户端侧 |
RouteToRequestUrl Filter |
将从request里获取的原始url转换成Gateway进行请求转发时所使用的url |
Websocket Routing Filter |
使用Spring Web Socket将转发 Websocket 请求 |
Gateway Metrics Filter |
整合监控相关,提供监控指标 |
本篇对Gateway的底层实现原理进行详细介绍,希望能对读者朋友们有所帮助。
作者介绍
波哥,互联行业从业10余年,先后担任项目总监及架构师。目前专攻技术,喜欢研究技术原理。技术全面,主攻Java,精通JVM底层机制及Spring全家桶底层框架原理,熟练掌握当前主流的中间件、服务网格等技术原理。