The introduction
Spring Cloud Gateway dynamic routing and built-in filters. In the spirit of probing, I can’t help but wonder how Spring Cloud Gateway’s filters are loaded. We all know about WebFlux in the Spring 5.x release, which is part of the Spring 5.x framework and provides responsive programming support for Web applications. The Spring Cloud Gateway is implemented based on WebFlux.
So today we’ll take a look at how Spring Cloud Gateway fits in with Web Flxu.
Gateway point
We know that requests are handled and forwarded by DispatcherServlet in SpringMVC, and Spring WebFlux has a similar class: DispatcherHandler
ServerWebExchange gets the Handler instance from the handlerMappings property based on the current request information and calls it.
@Override public Mono<Void> handle(ServerWebExchange exchange) { if (this.handlerMappings == null) { return createNotFoundError(); } if (CorsUtils.isPreFlightRequest(exchange.getRequest())) { return handlePreFlight(exchange); } return toggle. fromIterable(this.handlermappings) // getHandler instances. ConcatMap (mapping -> mapping.gethandler) .next().switchIfEmpty(createNotFoundError()) // Call the handler method. FlatMap (handler -> invokeHandler(exchange, FlatMap (result -> handleResult(exchange, result)); }Copy the code
Let’s look at the handlerMappings attribute, which is a List
List, and the value of the attribute is obtained from the Spring container using the initStrategies method.
protected void initStrategies(ApplicationContext context) { Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerMapping.class, true, false); ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values()); AnnotationAwareOrderComparator.sort(mappings); this.handlerMappings = Collections.unmodifiableList(mappings); . }Copy the code
Among the HandlerMapping instances, we can find one of the Spring Cloud Gateway implementation classes: RoutePredicateHandlerMapping, this class is passed in GatewayAutoConfiguration class @ Bean instantiation of the annotations, which also by constructor injection has an important example of this: RouteLocator.
Now, let’s go back to the handle method of the DispatcherHandler class, which returns some handler object by calling the HandlerApp #getHandler method, and then calling it.
So, among RoutePredicateHandlerMapping instance, getHandler method is actually call the parent class, which in turn calls the RoutePredicateHandlerMapping# getHandlerInternal method.
protected Mono<? > getHandlerInternal(ServerWebExchange exchange) { if (this.managementPortType == DIFFERENT && this.managementPort ! = null && exchange.getRequest().getURI().getPort() == this.managementPort) { return Mono.empty(); } exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName()); return lookupRoute(exchange) .flatMap((Function<Route, Mono<? >>) r -> { exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR); if (logger.isDebugEnabled()) { logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r); } // Cache the matched routing instance into the context of the current request exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); // Return FilteringWebHandler instance mono.just (webHandler); }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> { exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR); if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); }}))); }Copy the code
Will finally go the RoutePredicateHandlerMapping# lookupRoute method.
Protected Mono < Route > lookupRoute (ServerWebExchange exchange) {/ / traverse the Route list return this. RouteLocator. GetRoutes () .concatMap(route -> Mono.just(route).filterWhen(r -> { exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId()); // Determine whether the route matches return r.greetpredicate ().apply(exchange); }) .doOnError(e -> logger.error("Error applying predicate for route: " + route.getId(), e)) .onErrorResume(e -> Mono.empty())) .next() .map(route -> { if (logger.isDebugEnabled()) { logger.debug("Route matched: " + route.getId()); } validateRoute(route, exchange); return route; }); }Copy the code
As you already know, the route is finally matched against the current request, cached in the context of the current request information, and returned with the corresponding FilteringWebHandler instance.
Finally, put a RoutePredicateHandlerMapping class diagram
Gateway Filter processing flow
From the previous section, we saw how Gateway gets into the WebFlux process. Now let’s look at how the filter framework for the Spring Cloud Gateway is handled.
Before we talk about the Spring Cloud Gateway filter process, we need to know that there are two types of filters in the Gateway:
GlobalFilter
A filter of the common type that is loaded on all routesGatewayFilter
For a special type of filter, only the displayed filter is mounted to a filter, the corresponding logical processing will be performed
In the last section, we saw that the DispatcherHandler#handle method ends up doing two things:
- The routing object is matched based on the request information and placed in the context of the current request
- return
FilteringWebHandler
The instance
And then we go down and make a method call in the DispatcherHandler#invokeHandler method, which goes to FilteringWebHandler#handle.
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(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 DefaultGatewayFilterChain(combined).filter(exchange);
}
Copy the code
In this method, the Route object is retrieved from the context of the current request, the filters are assembled, the GlobalFilter and GatewayFilter are combined into a list, and then placed into the filter chain for logical processing.
conclusion
Through the above step by step combing, we finally understand how Spring Cloud Gateway is combined with WebFlux, and how the most important Filter works.
Above, if there is something wrong, welcome to discuss.
Add your personal wechat friends to discuss below: DaydayCoupons