Spring Cloud Gateway(三):網關處理器


1、Spring Cloud Gateway 源碼解析概述

API網關作為后端服務的統一入口,可提供請求路由、協議轉換、安全認證、服務鑒權、流量控制、日志監控等服務。那么當請求到達網關時,網關都做了哪些處理以及怎么處理的呢?我們帶着這些問題,順着網關的處理流程,一步步進行源碼閱讀,一探究竟。

2、Spring Cloud Gateway 網關處理流程概述

image

1、請求發送到網關, DispatcherHandler 是HTTP請求的中央分發器,將請求匹配到響應的HandlerMapping;

2、請求與處理器之間有一個映射關系,網關將會對請求進行路由,handler會匹配到RoutePredicateHandlerMapping,以匹配到對應的Route

3、接着請求到達網關的web處理器,該WebHandler 代理了一系列網關過濾器和全局過濾器的實例,此時會對請求頭或響應頭進行處理

4、最后轉發到具體的代理服務

3、Spring Cloud Gateway 初始化

當啟動網關服務時,引入的Spring Cloud Gateway 的starter將會自動加載一些配置:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
# WebFlux 依賴檢查配置類
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
# 網關核心自動配置類,配置路由規則、過濾器等
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
# 客戶端負載均衡自動配置類
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
# 網關指標自動配置類
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
# redis 自動配置類
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
# 服務發現客戶端自動配置類
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration

下面不會一一列出以上的配置,這里主要看一下設計網關屬性的配置。GatewayProperties是網關配置中的核心配置屬性類:

@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
    //路由列表    
    @NotNull
    @Valid
    private List<RouteDefinition> routes = new ArrayList();
    //默認過濾器
    private List<FilterDefinition> defaultFilters = new ArrayList();
    //流媒體類型
    private List<MediaType> streamingMediaTypes;

    public GatewayProperties() {
        this.streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON);
    }

    public List<RouteDefinition> getRoutes() {
        return this.routes;
    }

    public void setRoutes(List<RouteDefinition> routes) {
        this.routes = routes;
    }

    public List<FilterDefinition> getDefaultFilters() {
        return this.defaultFilters;
    }

    public void setDefaultFilters(List<FilterDefinition> defaultFilters) {
        this.defaultFilters = defaultFilters;
    }

    public List<MediaType> getStreamingMediaTypes() {
        return this.streamingMediaTypes;
    }

    public void setStreamingMediaTypes(List<MediaType> streamingMediaTypes) {
        this.streamingMediaTypes = streamingMediaTypes;
    }

    public String toString() {
        return "GatewayProperties{routes=" + this.routes + ", defaultFilters=" + this.defaultFilters + ", streamingMediaTypes=" + this.streamingMediaTypes + '}';
    }
}

GatewayProperties 有三個屬性,分別是路由列表(對應路由定義對象RouteDefinition)、默認過濾器列表(對應過濾器對象FilterDefinition)、流媒體類型列表(對應流媒體對象MediaType)

4、網關處理器

當請求到達網關時,會有各種web處理器對請求進行匹配和處理,下面我們將會對主要的幾個web處理器進行講解

image

graph LR
DispatcherHandler -->RoutePredicateHandlerMapping
RoutePredicateHandlerMapping-->FilteringWebHandler
FilteringWebHandler-->DefaultGatewayFilterChain

4.1、請求分發器 DispatcherHandler

Spring Cloud Gateway 引入了Spring WebFlux, DispatcherHandler 是 請求分發處理器,是網關請求的入口。之前的項目中引入的是 Spring MVC,它的分發 處理器是 DispatcherServlet。下面看一下網關收到請求后是如何處理的:

public class DispatcherHandler implements WebHandler, ApplicationContextAware {
    private static final Exception HANDLER_NOT_FOUND_EXCEPTION;
    private static final Log logger;
    @Nullable
    private List<HandlerMapping> handlerMappings;
    @Nullable
    private List<HandlerAdapter> handlerAdapters;
    @Nullable
    private List<HandlerResultHandler> resultHandlers;

    public DispatcherHandler() {
    }

    public DispatcherHandler(ApplicationContext applicationContext) {
        this.initStrategies(applicationContext);
    }

    @Nullable
    public final List<HandlerMapping> getHandlerMappings() {
        return this.handlerMappings;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.initStrategies(applicationContext);
    }


//根據請求匹配對應的出列器
    public Mono<Void> handle(ServerWebExchange exchange) {
        if (logger.isDebugEnabled()) {
            ServerHttpRequest request = exchange.getRequest();
            logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
        }

        return this.handlerMappings == null ? Mono.error(HANDLER_NOT_FOUND_EXCEPTION) : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
            return mapping.getHandler(exchange);
        }).next().switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)).flatMap((handler) -> {
            return this.invokeHandler(exchange, handler);
        }).flatMap((result) -> {
            return this.handleResult(exchange, result);
        });
    }
    
  
    private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
				if (handlerAdapter.supports(handler)) {
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}

	private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
		return getResultHandler(result).handleResult(exchange, result)
				.onErrorResume(ex -> result.applyExceptionHandler(ex).flatMap(exceptionResult ->
						getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
	}

	private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
		if (this.resultHandlers != null) {
			for (HandlerResultHandler resultHandler : this.resultHandlers) {
				if (resultHandler.supports(handlerResult)) {
					return resultHandler;
				}
			}
		}
		throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
	}
}

DispatcherHandler 實現了 WebHandler 接口,WebHandler 接口是用來處理 Web請求的。在DispatcherHandler 的構造函數中會初始化 HandlerMapping,核心 處理 的方法是 handle( ServerWebExchange exchange), 而 HandlerMapping 是一個定義 了請求與處理器對象映射的接口且有多個實現類,如 ControllerEndpointHandlerMapping 和 RouterFunctionMapping。

invokeHandler 方法調用相應的 WebHandler,獲取該WebHandler對應的適配器。

4.2、路由斷言處理器 RoutePredicateHandlerMapping

RoutePredicateHandlerMapping 用於匹配具體的Route,並返回處理 Route 的 FilteringWebHandler

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    private final FilteringWebHandler webHandler;
    private final RouteLocator routeLocator;

    public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties) {
        this.webHandler = webHandler;
        this.routeLocator = routeLocator;
        this.setOrder(1);
        this.setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
    }
    ................................
}

RoutePredicateHandlerMapping 的構造函數接受兩個參數,
FilteringWebHandler 網關過濾器 和 RouteLocator 路由定位器, setOrder( 1) 用於設置該對象初始化的優先級。

Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供的 HTTP API 不需要經過 網關轉發,它通過 RequestMappingHandlerMapping 進行請求匹配處理,因此需要將 RoutePredicateHandlerMapping 的優先級設置為 低於RequestMappingHandlerMapping。

 protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
 //設置網關處理器為 RoutePredicateHandlerMapping
        exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getClass().getSimpleName());
        return this.lookupRoute(exchange).flatMap((r) -> {
            exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);
            }

            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
            return Mono.just(this.webHandler);
        }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
            exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
            }

        })));
    }

    //路由順序匹配
    protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
        return this.routeLocator.getRoutes().concatMap((route) -> {
            return Mono.just(route).filterWhen((r) -> {
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                return (Publisher)r.getPredicate().apply(exchange);
            }).doOnError((e) -> {
                this.logger.error("Error applying predicate for route: " + route.getId(), e);
            }).onErrorResume((e) -> {
                return Mono.empty();
            });
        }).next().map((route) -> {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Route matched: " + route.getId());
            }
            //校驗路由有效性
            this.validateRoute(route, exchange);
            return route;
        });
    }

以上為獲取 handler 的方法,匹配請求的Route,並返回處理 Route的過濾器 FilteringWebHandler。

首先設置GATEWAY_ HANDLER_ MAPPER_ ATTR 為 RoutePredicateHandlerMapping 的類名

然后順序匹配對應的 Route,RouteLocator 接口獲取網關中定義的路由,並根據請求信息與路由定義的斷言按照優先級匹配。

最后找到匹配的Route,並返回響應的處理器。

4.3、過濾器處理器 FilteringWebHandler

FilteringWebHandler 通過創建所請求 Route 對應的 GatewayFilterChain, 在網關進行過濾處理

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) -> {
        //適配 GatewayFilter
            FilteringWebHandler.GatewayFilterAdapter gatewayFilter = new FilteringWebHandler.GatewayFilterAdapter(filter);
            //是否實現了 Ordered,如果實現了,則返回OrderedGatewayFilter
            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);
        logger.debug("Sorted gatewayFilterFactories: " + combined);
        //按照優先級對請求進行過濾
        return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);
    }
}

全局變量 globalFilters 是Spring Cloud Gateway 定義的全局過濾器,構造函數通過傳入全局過濾器,對過濾器進行適配。因為過濾器有優先級,loadFilters 該方法主要是判斷過濾器是否實現了 Ordered 接口,如果實現了則返回OrderedGatewayFilter,否則返回適配的過濾器。最后將適配的過濾器加入全局過濾器,並對過濾器進行排序,根據優先級對請求進行處理。

4.4、生成過濾器鏈

FilteringWebHandler 內部靜態類 DefaultGatewayFilterChain

 private static class DefaultGatewayFilterChain implements GatewayFilterChain {
        private final int index;
        private final List<GatewayFilter> filters;

        public 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 的 handle 方法,首先獲取請求對應的路由過濾器和全局過濾器,並將兩者合並。

然后對過濾器進行排序。

最后按照優先級生成過濾器鏈,對請求進行過濾處理。

過濾器鏈的生成是通過內部靜態類 DefaultGatewayFilterChain 實現的,該類實現了GatewayFilterChain 接口,最后對請求按照過濾器優先級進行過濾。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM