> 文章列表 > SpringCloud源码探析(五)-网关Gateway的使用

SpringCloud源码探析(五)-网关Gateway的使用

SpringCloud源码探析(五)-网关Gateway的使用

1.概述

在微服务架构中,网关提供了统一的对外访问入口(自身跨一个或多个服务),它保证了内部服务对外暴露的合理性与安全性、降低了服务之间访问的复杂性,是微服务架构中至关重要的一部分。在SpringCloud中网关主要包含两种:Zuul和Gateway,Zuul是基于Servlet实现的,属于阻塞式编程,而SpringCloud Gateway是基于Spring 5中提供的WebFlux,属于响应式编程的实现,具有更好的性能。本文将详细分析SpringCloud Gateway的使用以及其实现原理。

2.Gateway使用

2.1 网关作用

在微服务架构中,网关所处的位置如下图所示:
SpringCloud源码探析(五)-网关Gateway的使用
网关的主要功能如下:

(1)权限校验:校验用户身份,合法用户允许访问;
(2)路由转发:制定路由规则,根据路由映射到指定服务;
(3)请求限流:控制访问流量,当请求数量达到一定值时,限制部分访问;
(4)API监控:监控应用程序请求结果、请求数量等。

网关的优势在于:
(1)统一入口:为全部微服务提供一个唯一的入口,网关起到外部和内部的隔离作用,保障了后台服务的安全性;
(2)鉴权校验:识别每个请求的权限,拒绝不符合条件的请求;
(3)动态路由:将请求路由到不同的后台微服务中;
(4)减少耦合:减少客户端与服务端的耦合,服务可以独立发展,通过网关来做映射。

2.2 Gateway路由核心元素

SpringCloud源码探析(五)-网关Gateway的使用
Gateway在启动时会创建Netty Server,它会接收来自客户端的请求,收到请求后会根据路由规则匹符合条件的路由,请求会被该路由配置的过滤器依次进行拦截处理,再由Netty Client转移到服务目标,由微服务处理后返回,返回结果会再次被过滤器处理,最后才会返回给Client。这里涉及Route的核心概念如下:

  • Route:一个Gateway服务可以配置多个Route,一个Route由ID、转发URI和多个Predicates 、Filters 构成。处理请求时会按照优先级排序,找到第一个满足所有Predicates 的 Route;
  • Predicate:路由断言,判断请求是否符合要求,符合则转发到路由目的地(能够根据多种属性匹配:请求路径、方法、请求头header等)。一个Route可以包含多个Predicates;
  • Filter:过滤器包括了处理请求和响应的逻辑,可以分为 pre 和 post 两个阶段,PreFilter(请求前处理)可以做参数校验、流量监控、日志记录、修改请求内容等等,在PostFilter(请求后处理)可以做响应内容修改。Gateway 包括两类 Filter:全局 Filter、路由Filter。每种全局 Filter 全局只会有一个实例,会对所有的 Route 都生效。路由 Filter 是针对 Route进行配置的,不同的 Route 可以使用不同的参数,因此会创建不同的实例。

2.3 Gateway使用

2.3.1 引入pom

       <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId><version>2.2.10.RELEASE</version></dependency>

2.3.2 添加配置

spring:cloud:gateway:routes:- id: userserviceuri: lb://userservicepredicates:- Path=/user/**- id: orderserviceuri: lb://orderservicepredicates:- Path=/order/**

2.3.3 启动类

@Slf4j
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {public static void main(String[] args) {log.info("这是新的GatewayApplication");SpringApplication.run(GatewayApplication.class, args);}
}

2.3.4 运行结果

SpringCloud源码探析(五)-网关Gateway的使用
SpringCloud源码探析(五)-网关Gateway的使用

2.4 Gateway运行原理

2.4.1 路由原理

在这里插入图片描述
Gateway接收请求的流程如上图所示:

1.请求会先经过DispatcherHandler;
2.DispatcherHandler会根据RoutePredicateHandlerMapping获取Handler方法;
3.RoutePredicateHandlerMapping需要根据RouteLocator获取所有路由配置信息并匹配满足条件的路由;
4.RoutePredicateHandlerMapping会将请求交给FilteringWebHandler处理;
5.FilteringWebHandler从已经匹配的路由中获取对应的路由Filter,与全局Filter合并构造GatewayFilterChain,最终由GatewayFilterChain里的Filter按照顺序进行处理。

2.4.2 RouteLocator

一个Route主要包含以下几个属性:

属性名称 含义
Id 路由Id,具有唯一性
uri 转发请求的目标地址
Order 优先级
Predicate 规则(匹配条件),多个规则会合并成一个聚合条件
Filters 路由过滤器,这些过滤器与全局过滤器一起,按顺序处理请求并按要求返回结果
Metadata 额外的元数据

Gateway主要通过接口RouteLocator接口来获取路由配置,RouteLocator代码如下:

public interface RouteLocator {Flux<Route> getRoutes();}

在Gateway的源码中,RouteLocator的实现类主要有:RouteDefinitionRouteLocator、CompositeRouteLocator、CachingRouteLocator。它们之间的关系如下图所示:
SpringCloud源码探析(五)-网关Gateway的使用

RouteDefinitionLocator 提供RouteDefinition ,由 RouteDefinition 构造路由。可以存在多个RouteLocator ,这些实例提供的路由最终会由 CompositeRouteLocator 整合,再由 CachingRouteLocator 缓存。CachingRouteLocator 会把下层的 RouteLocator 返回的路由缓存起来,后续直接返回使用,同时监听RefreshRoutesEvent来定时刷新缓存的路由。

2.4.3 Predicate

Predicate接口提供了可以针对请求条件的匹配规则,匹配成功的路由负责处理该请求。路由是分优先级的,匹配时会根据优先级返回第一个匹配成功的路由,配置时匹配条件越具体(越详尽)的路由应配置更高的优先级,优先级从-2^31 到 2^31-1,值越小优先级越高。Gateway提供了很多基于Predicate的规则,比如Header、Host、Parameter、Request Method等,也可以实现接口RoutePredicateFactory自定义规则,RoutePredicateFactory接口代码如下:

@FunctionalInterface
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {// ...Predicate<ServerWebExchange> apply(C config);// ...
}

2.4.4 Filter

Gateway过滤器分为两种,全局过滤器和路由过滤器,全局 Filter会自动对所有的路由都生效,有些功能比如全局日志、请求时长等就比较适合设计成全局过滤器,这类过滤器对应的是 GlobalFilter 接口,自定义全局过滤器只需要实现该接口并注册到spring容器即可。

public interface GlobalFilter {Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);}

路由Filter是针对某个具体的路由进行配置,需要实现接口 GatewayFilterFactory,路由Filter主要针对具体路由进行不同配置,比如添加删减请求头参数、添加鉴权信息等。代码如下:

@FunctionalInterface
public interface GatewayFilterFactory<C> extends ShortcutConfigurable, Configurable<C> {// ...GatewayFilter apply(C config);// ...
}

上述两类 Filter 在处理请求之前会先放一起排序,通过Order注解或者实现 Ordered 接口声明进行声明,Gateway Filter 处理请求和响应相关的核心代码在 FilteringWebHandler 类,代码如下:

public class FilteringWebHandler implements WebHandler {protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);private final List<GatewayFilter> globalFilters;public FilteringWebHandler(List<GlobalFilter> globalFilters) {this.globalFilters = loadFilters(globalFilters);}private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {return (List)filters.stream().map((filter) -> {FilteringWebHandler.GatewayFilterAdapter gatewayFilter = new FilteringWebHandler.GatewayFilterAdapter(filter);if (filter instanceof Ordered) {int order = ((Ordered)filter).getOrder();return new OrderedGatewayFilter(gatewayFilter, order);} else {return gatewayFilter;}}).collect(Collectors.toList());}public Mono<Void> handle(ServerWebExchange exchange) {Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);List<GatewayFilter> gatewayFilters = route.getFilters();List<GatewayFilter> combined = new ArrayList(this.globalFilters);combined.addAll(gatewayFilters);AnnotationAwareOrderComparator.sort(combined);if (logger.isDebugEnabled()) {logger.debug("Sorted gatewayFilterFactories: " + combined);}return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);}private static class GatewayFilterAdapter implements GatewayFilter {private final GlobalFilter delegate;GatewayFilterAdapter(GlobalFilter delegate) {this.delegate = delegate;}public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return this.delegate.filter(exchange, chain);}public String toString() {StringBuilder sb = new StringBuilder("GatewayFilterAdapter{");sb.append("delegate=").append(this.delegate);sb.append('}');return sb.toString();}}private static class DefaultGatewayFilterChain implements GatewayFilterChain {private final int index;private final List<GatewayFilter> filters;DefaultGatewayFilterChain(List<GatewayFilter> filters) {this.filters = filters;this.index = 0;}private DefaultGatewayFilterChain(FilteringWebHandler.DefaultGatewayFilterChain parent, int index) {this.filters = parent.getFilters();this.index = index;}public List<GatewayFilter> getFilters() {return this.filters;}public Mono<Void> filter(ServerWebExchange exchange) {return Mono.defer(() -> {if (this.index < this.filters.size()) {GatewayFilter filter = (GatewayFilter)this.filters.get(this.index);FilteringWebHandler.DefaultGatewayFilterChain chain = new FilteringWebHandler.DefaultGatewayFilterChain(this, this.index + 1);return filter.filter(exchange, chain);} else {return Mono.empty();}});}}
}

由上述代码可知, FilteringWebHandler 会将所有的 GlobalFilter 实例加载进来并使用GatewayFilterAdapter 适配成 GatewayFilter。在handle()方法处理请求时,会将适配后的GlobalFilter 以及路由GatewayFilter合并在一个List中,根据Order进行排序,排序之后会构造一个GatewayFilterChain,由其中 filter() 方法触发这些 Filter 的执行。

3.小结

1.Gateway包含的核心元素主要有:Route、Predicate、Filter;
2.Gateway中路由过滤器分为全局过滤器和路由过滤器,全局过滤器和路由过滤器会根据Order排序执行;
3.Gateway主要通过接口RouteLocator接口来获取路由配置。

4.参考文献

1.https://www.bilibili.com/video/BV1LQ4y127n4
2.https://juejin.cn/post/6844903788680052750
3.https://spring.io/projects/spring-cloud-gateway

5.附录

https://gitee.com/Marinc/nacos.git

马大夫营养食疗