前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >请求处理流程

请求处理流程

作者头像
Reactor2020
发布2023-03-22 18:53:21
4660
发布2023-03-22 18:53:21
举报

Web处理流程

1、请求入口

代码语言:javascript
复制
//org.springframework.web.server.handler.FilteringWebHandler#handle
public Mono<Void> handle(ServerWebExchange exchange) {
    //chain类型:DefaultWebFilterChain
	return this.chain.filter(exchange);
}

1582624312263

2、执行WebFilterChain调用链

代码语言:javascript
复制
//org.springframework.web.server.handler.DefaultWebFilterChain#filter
public Mono<Void> filter(ServerWebExchange exchange) {
	return Mono.defer(() ->
			this.currentFilter != null && this.next != null ?
					this.currentFilter.filter(exchange, this.next) :
					this.handler.handle(exchange));
}

把每个WebFilter都包装成一个DefaultWebFilterChain,其中包含两个主要属性:当前封装的WebFilter以及下一个chain

代码语言:javascript
复制
private final WebFilter currentFilter;//当前WebFilter实例
private final DefaultWebFilterChain next;//下一个chain实例

这样把所有的WebFilter串成一个chain链,触发第一个DefaultWebFilterChain.filter()方法后就会按照chain链的顺序执行下去,最后一个WebFilter执行完成后,再去执行WebHandler,默认类型是:org.springframework.web.reactive.DispatcherHandler

总结起来就是,把WebFilter执行完成后,再去调用DispatcherHandler.handle(exchange)方法。

3、请求总控制器DispatcherHandler

代码语言:javascript
复制
//org.springframework.web.reactive.DispatcherHandler#handle
public Mono<Void> handle(ServerWebExchange exchange) {
    //校验handlerMappings是否为空
	if (this.handlerMappings == null) {
		return createNotFoundError();
	}
	return Flux.fromIterable(this.handlerMappings)//遍历handlerMappings集合进行请求处理
			.concatMap(mapping -> mapping.getHandler(exchange))//通过mapping获取对应的handler
			.next()
			.switchIfEmpty(createNotFoundError())
			.flatMap(handler -> invokeHandler(exchange, handler))//调用handler处理
			.flatMap(result -> handleResult(exchange, result));
}

1582104568844

遍历HandlerMapping获取mapping对应的handler,此处会找到RoutePredicateHandlerMapping,并获得handler(FilteringWebHandler)。我们来看下RoutePredicateHandlerMapping#getHandler方法执行逻辑。

首先,getHandler定义在父类AbstractHandlerMapping中,见下:

代码语言:javascript
复制
public Mono<Object> getHandler(ServerWebExchange exchange) {
	return getHandlerInternal(exchange).map(handler -> {//调用子类中getHandlerInternal()获取handler
		if (logger.isDebugEnabled()) {
			logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
		}
		if (CorsUtils.isCorsRequest(exchange.getRequest())) {//判断是否跨域
			CorsConfiguration configA = this.corsConfigurationSource.getCorsConfiguration(exchange);
			CorsConfiguration configB = getCorsConfiguration(handler, exchange);
			CorsConfiguration config = (configA != null ? configA.combine(configB) : configB);
			if (!getCorsProcessor().process(config, exchange) ||
					CorsUtils.isPreFlightRequest(exchange.getRequest())) {
				return REQUEST_HANDLED_HANDLER;
			}
		}
		return handler;
	});
}

RoutePredicateHandlerMapping#getHandlerInternal:根据exchange匹配对应的Route,并放置到exchangeattribute中,同时返回org.springframework.cloud.gateway.handler.FilteringWebHandler类型的hanler

代码语言:javascript
复制
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());

	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);
				}
				//将匹配到的Route放置到Attribute中
				exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
				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) + "]");
				}
			})));
}

接下来看下匹配Route逻辑代码lookupRoute()

代码语言:javascript
复制
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
	return this.routeLocator.getRoutes()//调用CachingRouteLocator#getRoutes从缓存中获取routes
			.concatMap(route -> Mono.just(route).filterWhen(r -> {
				exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());//
				return r.getPredicate().apply(exchange);//通过路由断言Predicate过滤掉不可用路由信息
			}).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;
			});
}

getHandlerInternal大致逻辑: 1、通过CachingRouteLocator#getRoutes从缓存中获取routesroutes加载流程上次《Route加载流程》一节已分析过; 2、遍历routes,并通过Route中的断言Predicate过滤掉不可用路由; 3、查找到路由信息后,通过exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r)设置到上下文环境中; 4、返回Gateway自定义的WebHandler(FilteringWebHandler)

Gateway处理流程

4、执行handler

RoutePredicateHandlerMapping获得org.springframework.cloud.gateway.handler.FilteringWebHandler,然后执行invokeHandler()

代码语言:javascript
复制
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
	if (this.handlerAdapters != null) {
        //遍历handlerAdapter列表,通过supports()方法找到支持该handler的Adapter
		for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
			if (handlerAdapter.supports(handler)) {
				return handlerAdapter.handle(exchange, handler);
			}
		}
	}
	return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

1582162794216

如上图显示,只有SimpleHandlerAdapter支持FilteringWebHandlerSimpleHandlerAdapter处理很简单,将handler转型成WebHandler,然后直接调用webHandler#handle

代码语言:javascript
复制
//org.springframework.web.reactive.result.SimpleHandlerAdapter#handle
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
	WebHandler webHandler = (WebHandler) handler;
	Mono<Void> mono = webHandler.handle(exchange);
	return mono.then(Mono.empty());
}

5、Gateway核心控制器FilteringWebHandler

FilteringWebHandler非前面说spring-web包中的FilteringWebHandler,而是位于gateway-core模块下,是请求进入gateway模块的核心入口。

代码语言:javascript
复制
//org.springframework.cloud.gateway.handler.FilteringWebHandler#handle
public Mono<Void> handle(ServerWebExchange exchange) {
    //获取匹配的Route,该Route是在RoutePredicateHandlerMapping中匹配并放置到exchange的attribute中的
	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);
	}

    //将过滤器封装到chain并执行filter方法
	return new DefaultGatewayFilterChain(combined).filter(exchange);
}

大致工作: 1、获取之前RoutePredicateHandlerMapping中放置到exchangeattribute中的Route对象; 2、然后从Route中获取的GatewayFilter和全局过滤器GlobalFilter进行合入并排序; 3、将所有的Filter包装成DefaultGatewayFilterChain,然后执行filter()方法;

1582163465104

接下来来分析下DefaultGatewayFilterChain执行流程,代码见下:

代码语言:javascript
复制
//DefaultGatewayFilterChain#filter
public Mono<Void> filter(ServerWebExchange exchange) {
	return Mono.defer(() -> {
		if (this.index < filters.size()) {
			GatewayFilter filter = filters.get(this.index);
			DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
			return filter.filter(exchange, chain);
		}
		else {
			return Mono.empty(); // complete
		}
	});
}

filter()方法中的代码逻辑可以看出,这里也是将所有的GatewayFilter进行包装构建成调用链chain,然后按照调用链顺序一个个执行GatewayFilter,这里的**chain调用链构建原理参照上面WebFilter调用链**创建过程。

总结

image-20200227004515360

Gateway请求处理流程大致可以绘制成上面图,其中浅绿色为spring-web部分流程,然后进入到gateway代码部分(浅蓝色部分);其中,交界处RoutePredicateHandler会从CachingRouteLocator缓存的routes,然后基于Predicate进行匹配过滤出当前符合当前请求的Route,然后开始真正进入Gateway处理流程,基于GatewayFilter扩展出各种业务功能。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Reactor2020 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Web处理流程
  • Gateway处理流程
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档