SpringCloudGateway源码阅读(二)请求流程解读

3,116 阅读5分钟

前言

本章主要介绍一个Http请求的请求流程,下面是请求流程的流程图。

需要注意的是,这个请求流程中有个同名不同包的类,org.springframework.web.server.handler.FilteringWebHandler是SpringWeb的,org.springframework.cloud.gateway.handler.FilteringWebHandler是Gateway的,都实现了WebHandler接口,容易混淆。

一、DispatcherHandler之前

HttpWebHandlerAdapter#handle创建ServerWebExchange,委托ExceptionHandlingWebHandler处理handle方法。

@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
	// 创建ServerWebExchange
	ServerWebExchange exchange = createExchange(request, response);

	// 委托ExceptionHandlingWebHandler#handle
	return getDelegate().handle(exchange)
			.doOnSuccess(aVoid -> logResponse(exchange))
			.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
			.then(Mono.defer(response::setComplete));
}
protected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {
    return new DefaultServerWebExchange(request, response, this.sessionManager,
            getCodecConfigurer(), getLocaleContextResolver(), this.applicationContext);
}

ExceptionHandlingWebHandler#handle委托spring-webFilteringWebHandler处理handle方法。

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	Mono<Void> completion;
	try {
		// org.springframework.web.server.handler.WebHandlerDecorator#handle
		// 委托org.springframework.web.server.handler.FilteringWebHandler#handle
		completion = super.handle(exchange);
	}
	catch (Throwable ex) {
		completion = Mono.error(ex);
	}
	// 全局异常处理
	for (WebExceptionHandler handler : this.exceptionHandlers) {
		completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
	}
	return completion;
}

FilteringWebHandler#handle执行WebFilter过滤器链。

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	// 执行WebFilterChain的filter方法
	return this.chain.filter(exchange);
}

DefaultWebFilterChain#filter执行所有WebFilter,执行完毕后执行DispatcherHandler。

public class DefaultWebFilterChain implements WebFilterChain {
	// 所有过滤器
	private final List<WebFilter> allFilters;
	// DispatcherHandler
	private final WebHandler handler;
	// 当前需要执行的过滤器
	private final WebFilter currentFilter;
	// 剩下需要处理的过滤器链
	private final DefaultWebFilterChain chain;
	@Override
	public Mono<Void> filter(ServerWebExchange exchange) {
		return Mono.defer(() ->
				this.currentFilter != null && this.chain != null ?
						// 执行WebFilter
						invokeFilter(this.currentFilter, this.chain, exchange) :
						// 执行DispatcherHandler
						this.handler.handle(exchange));
	}
	private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
		String currentName = current.getClass().getName();
		return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
	}

二、DispatcherHandler执行流程

DispatcherHandler#handle和SpringMVC的DispatcherServlet类似。

public class DispatcherHandler implements WebHandler, ApplicationContextAware {
	private List<HandlerMapping> handlerMappings;
	private List<HandlerAdapter> handlerAdapters;
	private List<HandlerResultHandler> resultHandlers;
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		return Flux.fromIterable(this.handlerMappings)
				// 按照优先级执行HandlerMapping的getHandler方法获取handler
				// 抽象父类AbstractHandlerMapping#getHandler会调用子类的getHandlerInternal方法
				.concatMap(mapping -> mapping.getHandler(exchange))
				// 取得到的第一个handler
				.next()
				// 找不到handler抛异常
				.switchIfEmpty(createNotFoundError())
				// 循环HandlerAdapter,找到合适的Adapter执行handler
				.flatMap(handler -> invokeHandler(exchange, handler))
				// 循环HandlerResultHandler,找到合适的执行handleResult方法返回客户端
				.flatMap(result -> handleResult(exchange, result));
	}
}

RoutePredicateHandlerMapping

RoutePredicateHandlerMapping根据ServerWebExchange获取Handler,将Route实例放入ServerWebExchange的Attribute中,后续一直会用到exchange实例里的Route实例。

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
	private final FilteringWebHandler webHandler;
	private final RouteLocator routeLocator;
	public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
			RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
			Environment environment) {
		this.webHandler = webHandler;
		this.routeLocator = routeLocator;
		setOrder(1);
	}
}

getHandlerInternal根据ServerWebExchange,找到Route放入ServerWebExchange的Attribute,返回FilteringWebHandler实例。

@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
	// GATEWAY_HANDLER_MAPPER_ATTR = 'RoutePredicateHandlerMapping'
	exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

	// 根据exchange找到Route实例
	return lookupRoute(exchange)
			.flatMap((Function<Route, Mono<?>>) r -> {
				// 移除lookupRoute添加的Attribute:GATEWAY_PREDICATE_ROUTE_ATTR
				exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
				// 把Route实例放入Attribute
				// 后续Gateway的Filter基本都会用到这个Route实例,很重要
				exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
				// 返回FilteringWebHandler实例
				return Mono.just(webHandler);
			}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
				// 移除lookupRoute添加的Attribute:GATEWAY_PREDICATE_ROUTE_ATTR
				exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
			})));
}
// 根据ServerWebExchange找到Route
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
// CachingRouteLocator获取Route
return this.routeLocator.getRoutes()
		// 调用Route的断言的apply方法,过滤出满足条件的Route
		.concatMap(route -> Mono.just(route).filterWhen(r -> {
			exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
			return r.getPredicate().apply(exchange);
		})
		.doOnError(e -> logger.error(
				"Error applying predicate for route: " + route.getId(),
				e))
		.onErrorResume(e -> Mono.empty()))
		// 选取第一个过滤出来的Route
		.next()
		.map(route -> {
			// 校验Route,默认空实现
			validateRoute(route, exchange);
			return route;
		});
}

FilteringWebHandler

SimpleHandlerAdapter#handle执行FilteringWebHandler

public class SimpleHandlerAdapter implements HandlerAdapter {
	@Override
	public boolean supports(Object handler) {
		return WebHandler.class.isAssignableFrom(handler.getClass());
	}
	@Override
	public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
		WebHandler webHandler = (WebHandler) handler;
		Mono<Void> mono = webHandler.handle(exchange);
		return mono.then(Mono.empty());
	}
}

FilteringWebHandler执行所有GatewayFilter。

public class FilteringWebHandler implements WebHandler {
	private final List<GatewayFilter> globalFilters;

	public FilteringWebHandler(List<GlobalFilter> globalFilters) {
		// 这里会把GlobalFilter全局过滤器适配成GatewayFilter,逻辑省略
		this.globalFilters = loadFilters(globalFilters);
	}
	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		// RoutePredicateHandlerMapping#getHandlerInternal的时候放入的Route实例
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		// 获取Route实例上的GatewayFilter
		List<GatewayFilter> gatewayFilters = route.getFilters();
		// 组合全局GatewayFilter
		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
		// 排序
		AnnotationAwareOrderComparator.sort(combined);
		// DefaultGatewayFilterChain.filter执行网关过滤器链
		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}
}

DefaultGatewayFilterChain通过filters列表和移动下标的方式串联成一个过滤器链。

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(DefaultGatewayFilterChain parent, int index) {
		this.filters = parent.getFilters();
		this.index = index;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange) {
		return Mono.defer(() -> {
			// 如果还有过滤器没执行,则执行
			if (this.index < filters.size()) {
				// 获取当前过滤器
				GatewayFilter filter = filters.get(this.index);
				// 移动下标,构造一个新的链表(只是移动了下标,filters还是原始的filters)
				// 给后续执行的filter调用chain.filter
				DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
						this.index + 1);
				// 执行filter
				return filter.filter(exchange, chain);
			}
			else {
				return Mono.empty();
			}
		});
	}

}

三、重要的GlobalFilter

RouteToRequestUrlFilter

用Route的URI,替换原始请求url里的协议、host、port。如原始请求为: http://localhost:60261/httpbin/get,替换为lb://httpbin/httpbin/get,协议由http替换为lb,localhost:60261替换为httpbin。

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
	// 原始URL
	URI uri = exchange.getRequest().getURI();
	// Route的URL
	URI routeUri = route.getUri();

	URI mergedUrl = UriComponentsBuilder.fromUri(uri)
			// 协议替换
			.scheme(routeUri.getScheme())
			// host替换
			.host(routeUri.getHost())
			// 端口替换
			.port(routeUri.getPort())
			.build(encoded).toUri();
	// 保存合并后的url
	exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);
	return chain.filter(exchange);
}

LoadBalancerClientFilter

使用Ribbon的LoadBalancerClient重构请求URL。

public class LoadBalancerClientFilter implements GlobalFilter, Ordered {
	public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;

	protected final LoadBalancerClient loadBalancer;

	private LoadBalancerProperties properties;

	public LoadBalancerClientFilter(LoadBalancerClient loadBalancer,
			LoadBalancerProperties properties) {
		this.loadBalancer = loadBalancer;
		this.properties = properties;
	}

	@Override
	public int getOrder() {
		return LOAD_BALANCER_CLIENT_FILTER_ORDER;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
		String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
		// 非lb协议直接通过
		if (url == null
				|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
			return chain.filter(exchange);
		}
		// 保存原始url
		addOriginalRequestUrl(exchange, url);
		// 使用负载均衡策略,获取ServiceInstance
		final ServiceInstance instance = choose(exchange);
		if (instance == null) {
			throw NotFoundException.create(properties.isUse404(),
					"Unable to find instance for " + url.getHost());
		}
		// 获取schema,attribute里的优先,其次是ServiceInstance.isSecure
		URI uri = exchange.getRequest().getURI();
		String overrideScheme = instance.isSecure() ? "https" : "http";
		if (schemePrefix != null) {
			overrideScheme = url.getScheme();
		}
		// reconstructURI重构URL
		URI requestUrl = loadBalancer.reconstructURI(
				new DelegatingServiceInstance(instance, overrideScheme), uri);

		if (log.isTraceEnabled()) {
			log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
		}
		// 设置请求URL
		exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
		return chain.filter(exchange);
	}

	protected ServiceInstance choose(ServerWebExchange exchange) {
		return loadBalancer.choose(
				((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());
	}

}

NettyRoutingFilter

请求后端服务。重点关注一下连接超时时间、响应超时时间的获取。

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
	ServerHttpRequest request = exchange.getRequest();
	final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
	final String url = requestUrl.toASCIIString();

	boolean preserveHost = exchange
			.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
	Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
	// 获取HttpClientConnect
	Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
			.headers(headers -> {
				// 请求头处理...
			}).request(method).uri(url).send((req, nettyOutbound) -> {
				return nettyOutbound.send(request.getBody().map(this::getByteBuf));
				// responseConnection发起请求
			}).responseConnection((res, connection) -> {
				// 返回响应
				return Mono.just(res);
			});

	// 获取响应超时时间
	Duration responseTimeout = getResponseTimeout(route);
	if (responseTimeout != null) {
		// 响应超时处理
		responseFlux = responseFlux
				.timeout(responseTimeout, Mono.error(new TimeoutException(
						"Response took longer than timeout: " + responseTimeout)))
				.onErrorMap(TimeoutException.class,
						th -> new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT,
								th.getMessage(), th));
	}
	return responseFlux.then(chain.filter(exchange));
}

getHttpClient获取HttpClient,可以用Route的Metadata的CONNECT_TIMEOUT_ATTR属性,定制连接超时时间。默认取httpClient构造时的配置,默认45秒spring.cloud.gateway.httpclient.connectTimeout=4500

protected HttpClient getHttpClient(Route route, ServerWebExchange exchange) {
	Object connectTimeoutAttr = route.getMetadata().get(CONNECT_TIMEOUT_ATTR);
	if (connectTimeoutAttr != null) {
		Integer connectTimeout = getInteger(connectTimeoutAttr);
		return this.httpClient.tcpConfiguration((tcpClient) -> tcpClient
				.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout));
	}
	return httpClient;
}

getResponseTimeout获取响应超时时间,优先取Route的Metadata里的RESPONSE_TIMEOUT_ATTR属性,默认取spring.cloud.gateway.httpclient.responseTimeout为空,没有响应超时时间。

private Duration getResponseTimeout(Route route) {
	Object responseTimeoutAttr = route.getMetadata().get(RESPONSE_TIMEOUT_ATTR);
	Long responseTimeout = null;
	if (responseTimeoutAttr != null) {
		if (responseTimeoutAttr instanceof Number) {
			responseTimeout = ((Number) responseTimeoutAttr).longValue();
		}
		else {
			responseTimeout = Long.valueOf(responseTimeoutAttr.toString());
		}
	}
	return responseTimeout != null ? Duration.ofMillis(responseTimeout)
			: properties.getResponseTimeout();
}

NettyWriteResponseFilter

Mono.then写response

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  return chain.filter(exchange)
          .doOnError(throwable -> cleanup(exchange))
          .then(Mono.defer(() -> {
              Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);
              if (connection == null) {
                  return Mono.empty();
              }
              ServerHttpResponse response = exchange.getResponse();

              final Flux<DataBuffer> body = connection
                      .inbound()
                      .receive()
                      .retain()
                      .map(byteBuf -> wrap(byteBuf, response));

              MediaType contentType = response.getHeaders().getContentType();
              return (isStreamingMediaType(contentType)
                      ? response.writeAndFlushWith(body.map(Flux::just))
                      : response.writeWith(body));
          })).doOnCancel(() -> cleanup(exchange));
}

总结

  • 请求流程中关键的两个类
    • RoutePredicateHandlerMapping断言匹配获取Route
    • FilteringWebHandler执行所有GatewayFilter
  • LoadBalancerClientFilter利用Ribbon的LoadBalancerClient实现负载均衡
  • SpringCloudGateway调用后端服务的两个超时时间需要自己配置一下