Spring Cloud Gateway源码解析-04-路由匹配RoutePredicateHandlerMapping


系列文章

创作不易,如果对您有帮助,麻烦辛苦下小手点个关注,有任何问题都可以私信交流哈。
祝您虎年虎虎生威。


Spring Cloud Gateway源码解析-02-初始化解析之Route、Predicate、Filter的构建原理文章我们了解了Route、Predicate、Filter是如何根据我们的配置创建的,这篇文章我们来继续了解SCG是如何处理我们的请求的。
首先掏出来我们的祖传图,很关键。
在这里插入图片描述



SCG是基于webflux的,webflux和springweb-mvc类似,通过HandlerMapping来接收处理请求。
通过上图可以看到Client请求首先会到Gateway HanderMapping,那可以猜到这个HandlerMapping一定是webflux的HandlerMaping的实现类,这个GatewayHandlerMapping就是RoutePredicateHandlerMapping
RoutePredicateHandlerMapping是如何接收并处理我们的请求的呢?

由来

RoutePredicateHandlerMapping也是在GatewayAutoConfiguration中进行装配的

/**
	 *
	 * @param webHandler 上边装配的FilteringWebHandler
	 * @param routeLocator 上边装配的CachingRouteLocator
	 */
	@Bean
	public RoutePredicateHandlerMapping routePredicateHandlerMapping(
			FilteringWebHandler webHandler, RouteLocator routeLocator,
			GlobalCorsProperties globalCorsProperties, Environment environment) {
		return new RoutePredicateHandlerMapping(webHandler, routeLocator,
				globalCorsProperties, environment);
	}


在这里插入图片描述

在springmvc中有一个核心类DispatcherServlet,而对应webflux有一个核心类DispatcherHandler同是请求的入口。从网上找到了一张更加清晰的流程图
在这里插入图片描述

DispatcherHander的#handler方法用来匹配不同的handlerMapping来处理请求

@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				//根据获取到的handler进行处理
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}

通过debug可以看到我们的RoutePredicateHandlerMapping就在其中
在这里插入图片描述

public interface HandlerMapping {
 
  	Mono<Object> getHandler(ServerWebExchange exchange);
}

AbstractHandlerMapping中实现了HandlerMapping的handler方法

public abstract class AbstractHandlerMapping extends ApplicationObjectSupport
		implements HandlerMapping, Ordered, BeanNameAware {
  
  @Override
	public Mono<Object> getHandler(ServerWebExchange exchange) {
    //调用子类(RoutePredicateHandlerMapping)实现获取handler
		return getHandlerInternal(exchange).map(handler -> {
			if (logger.isDebugEnabled()) {
				logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
			}
			ServerHttpRequest request = exchange.getRequest();
			if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
				CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
				CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
				config = (config != null ? config.combine(handlerConfig) : handlerConfig);
				if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
					return REQUEST_HANDLED_HANDLER;
				}
			}
			return handler;
		});
	}
	protected abstract Mono<?> getHandlerInternal(ServerWebExchange exchange);
}

SCG的RoutePredicateHandlerMapping继承了AbstractHandlerMapping实现了getHandlerInternal方法
此方法将我们的路由信息放入了上下文中,并返回了FilteringWebHandler即FilteringWebHandler后边的文章会讲解。

@Override
	protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
		// don't handle requests on management port if set and different than server port
		if (this.managementPortType == DIFFERENT && this.managementPort != null
				&& exchange.getRequest().getURI().getPort() == this.managementPort) {
			return Mono.empty();
		}
		exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
		//这里可以看到调用了#lookupRoute去查找路由
		return lookupRoute(exchange)
				// .log("route-predicate-handler-mapping", Level.FINER) //name this
				.flatMap((Function<Route, Mono<?>>) r -> {
					exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
					if (logger.isDebugEnabled()) {
						logger.debug(
								"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
					}
					//将路由信息放入上下文中
					exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
					//返回webHandler,即FilteringWebHandler
					return 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) + "]");
					}
				})));
	}

lookupRoute方法是用来查找真正的路由信息

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
		return this.routeLocator.getRoutes()
				// individually filter routes so that filterWhen error delaying is not a
				// problem
				.concatMap(route -> Mono.just(route).filterWhen(r -> {
					// add the current route we are testing
					exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
					//根据断言获取到真正的Route
					return r.getPredicate().apply(exchange);
				})
						// instead of immediately stopping main flux due to error, log and
						// swallow it
						.doOnError(e -> logger.error(
								"Error applying predicate for route: " + route.getId(),
								e))
						.onErrorResume(e -> Mono.empty()))
				// .defaultIfEmpty() put a static Route not found
				// or .switchIfEmpty()
				// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
				.next()
				// TODO: error handling
				.map(route -> {
					if (logger.isDebugEnabled()) {
						logger.debug("Route matched: " + route.getId());
					}
					//校验方法并没有实现,可以自己继承实现
					validateRoute(route, exchange);
					return route;
				});

	}

至此,就获取到了SCG处理的handler和Route信息,今天太晚了就到这里了,后边解析如何进行处理的以及SCG的Filter是如何作用的。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
如果你想禁用Spring Cloud Gateway中的Swagger资源,可以在Gateway中添加一个过滤器来实现。 首先,在你的Gateway应用程序中,你需要创建一个过滤器类。这个过滤器将使用Spring Cloud Gateway中的RouteLocator来查找Swagger资源,然后将它们过滤掉。下面是一个示例过滤器类: ```java @Component public class SwaggerResourceFilter implements GlobalFilter, Ordered { @Autowired private RouteLocator routeLocator; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String requestPath = request.getPath().toString(); // 获取所有的路由 List<Route> routes = routeLocator.getRoutes().collectList().block(); // 遍历路由,查找是否包含Swagger资源 for (Route route : routes) { String routePath = route.getUri().toString(); if (requestPath.startsWith(routePath) && route.getMetadata().containsKey("swagger")) { // 如果请求路径包含Swagger资源,直接返回 return Mono.empty(); } } // 如果请求路径不包含Swagger资源,继续执行过滤器链 return chain.filter(exchange); } @Override public int getOrder() { return -1; } } ``` 在这个过滤器类中,我们首先使用RouteLocator获取所有的路由,然后遍历这些路由,查找是否包含Swagger资源。如果请求路径包含Swagger资源,直接返回,否则继续执行过滤器链。 接下来,在你的Gateway配置文件中,添加以下代码来注册这个过滤器类: ```yaml spring: cloud: gateway: default-filters: - SwaggerResourceFilter ``` 这将会在Gateway启动时自动注册这个过滤器类。当你访问Swagger资源时,Gateway将会过滤掉这些资源,从而禁用它们。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

壹氿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值