1、SpringCloud之Gateway源码解析

核心概念:

  1. 路由:基础部分,路由信息包括路由ID、目标uri、一组断言和一组过滤器组成。如果断言为真,则说明请求的url和配置匹配。
  2. 断言:Java8种断言函数。
  3. 过滤器:Gateway Filter & Global Filter。

自动配置类GatewayAutoConfiguration在内部初始化了很多bean,列举几个重要的如下:

  1. PropertiesRouteDefinitionLocator:用于从配置文件(yml/properties)中读取路由配置信息。
  2. RouteDefinitionLocator:把 RouteDefinition 转化为 Route。
  3. RoutePredicateHandlerMapping:类似于 mvc 的HandlerMapping,不过这里是Gateway实现的。用于匹配对应的请求route。 GatewayProperties:yml配置信息封装在GatewayProperties 对象中。
  4. AfterRoutePredicateFactory:各种路由断言工厂,正是这些断言工厂在启动时已经生成对应的bean,我们才可以在yml 中配置一下,即可生效。
  5. RetryGatewayFilterFactory:各种 Gateway过滤器,正是这些过滤器在启动时已经生成对应的bean,我们才可以在 yml 中配置一下,即可生效。
  6. GlobalFilter实现类:全局过滤器。

参考文章

本文大概:

  1. handlerMapping通过 Route 获取的Predicate断言匹配路由。
  2. 匹配成功之后将 Route 被 ServerWebExchange 持有。
  3. 通过handlerMapping获取处理器handler。
  4. handler通过Route获取gatewayFilter。
  5. handler获取全局过滤器。
  6. 递归执行全部的过滤器。

1、HttpServerHandle

Netty获取到客户端连接后,开始获取handler。文章从 HttpServerHandle 开始解析HTTP请求。

public void onStateChange(Connection connection, State newState) {
	// ops:请求 & 响应
	HttpServerOperations ops = (HttpServerOperations) connection;
			//handler:ReactorHttpHandlerAdapter
			Mono.fromDirect(handler.apply(ops, ops))
			    .subscribe(ops.disposeSubscriber());
}

1.1、ReactorHttpHandlerAdapter

public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
	ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
	ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
	// ReactiveWebServerApplicationContext
	return this.httpHandler.handle(request, response)
			.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
			.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
}

1.2、HttpWebHandlerAdapter

public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
	if (this.forwardedHeaderTransformer != null) {
		request = this.forwardedHeaderTransformer.apply(request);
	}
	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));
}

1.3、FilteringWebHandler

public Mono<Void> handle(ServerWebExchange exchange) {
	// DefaultWebFilterChain
	return this.chain.filter(exchange);
}

1.4、DefaultWebFilterChain

该filter方法存在递归调用。订阅者与发布者之间建立订阅关系后,首次调用执行invokeFilter其返回的还是发布者defer,根据引用得知,流式处理中会再次调用defer中的函数式接口Supplier默认方法,此时执行DispatcherHandler。

public Mono<Void> filter(ServerWebExchange exchange) {
	
	return Mono.defer(() ->
			// 初始化的过滤器 WeightCalculatorWebFilter
			this.currentFilter != null && this.chain != null ?
					invokeFilter(this.currentFilter, this.chain, exchange) :
					// DispatcherHandler
					this.handler.handle(exchange));
}
  1. DefaultWebFilterChain 属性中包含自身引用的属性chain。实例化过程中除了实例化本身之外,还会初始化其自身属性chain。此时的属性chain是没有初始化其自身的属性chain以及handler。
  2. 响应式规范下的Java 框架reactor库中,对于发布者defer其存在嵌套调用的情况。【源码比较直观】

HttpServerHandle的主要作用是得到DispatcherHandler

2、DispatcherHandler

2.1、通过handlerMapping获取handler

public Mono<Void> handle(ServerWebExchange exchange) {
	if (this.handlerMappings == null) {
		return createNotFoundError();
	}
	return Flux.fromIterable(this.handlerMappings)
			// RoutePredicateHandlerMapping匹配路由 & 跨域处理
			.concatMap(mapping -> mapping.getHandler(exchange))
			.next()//
			.switchIfEmpty(createNotFoundError())// 如果路由匹配失败,也就是返回Mono.empty,则直接抛出404异常
			// 路由匹配成功后返回Handler,FilteringWebHandler
			.flatMap(handler -> invokeHandler(exchange, handler))
			.flatMap(result -> handleResult(exchange, result));
}

handlerMappings:

  1. RouterFunctionMapping。
  2. RequestMappingHandlerMapping。
  3. RoutePredicateHandlerMapping【路由匹配】。#3
  4. SimpleUrlHandlerMapping。

2.2、Handler适配器

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));
}
  1. RequestMappingHandlerAdapter。
  2. HandlerFunctionAdapter。
  3. SimpleHandlerAdapter【支持】。

2.3、SimpleHandlerAdapter适配器处理Filter

通过适配器获取并执行全部过滤器。

public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
	WebHandler webHandler = (WebHandler) handler;
	// FilteringWebHandler
	Mono<Void> mono = webHandler.handle(exchange);
	return mono.then(Mono.empty());
}

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);
	// TODO: needed or cached?
	AnnotationAwareOrderComparator.sort(combined);
	return new DefaultGatewayFilterChain(combined).filter(exchange);
}
  1. 从Route获取GatewayFilter。其中就包括配置routes下的filters选项。【限流相关的过滤器参考】
  2. 获取全局过滤器。
  3. GatewayFilterFactory默认情况会初始化30种类型的过滤器工厂类,其创建的GatewayFilter均是匿名内部类方式。DefaultGatewayFilterChain在执行GatewayFilter时会回调匿名内部类过滤逻辑。

限流效果:

1、SpringCloud之Gateway源码解析_第1张图片

3、RoutePredicateHandlerMapping路由匹配

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);
				// 路由匹配通过之后,将 Route 对象作为ServerWebExchange的GATEWAY_ROUTE_ATTR属性。
				exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
				return Mono.just(webHandler);
			}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
				exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
			})));
}
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
	//routeLocator:CachingRouteLocator
	return this.routeLocator.getRoutes()
			.concatMap(route -> Mono.just(route).filterWhen(r -> {
				// add the current route we are testing
				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()))
			.next()
			// TODO: error handling
			.map(route -> {
				validateRoute(route, exchange);
				return route;
			});
}
  1. Predicate断言 & Filter 均是有Route持有。
  2. 通过 Route 获取到Predicate断言,执行路由的匹配。
  3. Route 对象被ServerWebExchange持有。【目的是执行过滤器功能】

4、过滤器

过滤器主要分为两种:GatewayFilter & GlobalFilter。

4.1、GlobalFilter

全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。

过滤器order值越小优先级越高:

  1. RemoveCachedBodyFilter。
  2. AdaptCachedBodyGlobalFilter。
  3. NettyWriteResponseFilter。
  4. ForwardPathFilter:处理重定向。
  5. RouteToRequestUrlFilter。
  6. LoadBalancerClientFilter。
  7. WebsocketRoutingFilter:处理webSocket类型的请求。
  8. NettyRoutingFilter:发送HTTP请求。
  9. ForwardRoutingFilter。
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;
	}

	public List<GatewayFilter> getFilters() {
		return filters;
	}

	@Override
	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
			}
		});
	}

}

4.1.1、NettyWriteResponseFilter

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	
	return chain.filter(exchange)
			// 这个cleanup()的作用是关闭连接,此处的意思是出错时关闭response connection
			.doOnError(throwable -> cleanup(exchange))
			.then(Mono.defer(() -> {
				// 1.从exchange拿到response connection,它是被NettyRoutingFilter发请求后塞进去的
				Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);
				if (connection == null) {
					return Mono.empty();
				}
				// 2.从connection接收字节流写入response
				ServerHttpResponse response = exchange.getResponse();
				NettyDataBufferFactory factory = (NettyDataBufferFactory) response
						.bufferFactory();
				final Flux<NettyDataBuffer> body = connection
						.inbound()
						.receive()
						.retain()
						.map(factory::wrap);
				MediaType contentType = response.getHeaders().getContentType();
				// 3.针对response是否为流媒体内容采取不同的返回调用,最终就返回给请求方了
				return (isStreamingMediaType(contentType)
						? response.writeAndFlushWith(body.map(Flux::just))
						: response.writeWith(body));
			})).doOnCancel(() -> cleanup(exchange));
	// @formatter:on
}

4.1.2、RouteToRequestUrlFilter

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
	if (route == null) {
		return chain.filter(exchange);
	}
	URI uri = exchange.getRequest().getURI();
	boolean encoded = containsEncodedParts(uri);
	URI routeUri = route.getUri();

	if (hasAnotherScheme(routeUri)) {
		exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR,
				routeUri.getScheme());
		routeUri = URI.create(routeUri.getSchemeSpecificPart());
	}

	if ("lb".equalsIgnoreCase(routeUri.getScheme()) && routeUri.getHost() == null) {
		throw new IllegalStateException("Invalid host: " + routeUri.toString());
	}
	
	URI mergedUrl = UriComponentsBuilder.fromUri(uri)
			// .uri(routeUri)
			.scheme(routeUri.getScheme()).host(routeUri.getHost())
			.port(routeUri.getPort()).build(encoded).toUri();
	exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);
	return chain.filter(exchange);
}
  1. uri:http://localhost:8096/gw/3?token=1。
  2. mergedUrl:lb:provider-service/gw/3?token=1。
  3. GATEWAY_REQUEST_URL_ATTR:gatewayRequestUrl。

4.1.3、LoadBalancerClientFilter

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);//lb:provider-service/gw/3?token=1
	String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
	// preserve the original url
	addOriginalRequestUrl(exchange, url);
	// 通过Ribbon客户端负载均衡获取目标服务IP、port等信息
	final ServiceInstance instance = choose(exchange);
	URI uri = exchange.getRequest().getURI();

	// if the `lb:` mechanism was used, use `` as the default,
	// if the loadbalancer doesn't provide one.
	String overrideScheme = instance.isSecure() ? "https" : "http";
	if (schemePrefix != null) {
		overrideScheme = url.getScheme();
	}
	// 通过负载均衡策略获取到目标服务的某个IP & 端口,拼接成为目标URI
	URI requestUrl = loadBalancer.reconstructURI(
			new DelegatingServiceInstance(instance, overrideScheme), uri);
	exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
	return chain.filter(exchange);
}
protected ServiceInstance choose(ServerWebExchange exchange) {
	//RibbonLoadBalancerClient
	return loadBalancer.choose(
			((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());
}

4.1.4、NettyRoutingFilter

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

	String scheme = requestUrl.getScheme();
	//如果请求已经被标记为已经被路由过了
	if (isAlreadyRouted(exchange)
			|| (!"http".equals(scheme) && !"https".equals(scheme))) {
		return chain.filter(exchange);
	}
	// 否则就标记为已经被路由过了,避免被其他路由处理
	setAlreadyRouted(exchange);
	ServerHttpRequest request = exchange.getRequest();
	final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
	final String url = requestUrl.toASCIIString();
	HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);
	final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
	filtered.forEach(httpHeaders::set);

	boolean preserveHost = exchange
			.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
	Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
	
	Flux<HttpClientResponse> responseFlux = httpClientWithTimeoutFrom(route)//设置超时时间
			.headers(headers -> {
				headers.add(httpHeaders);
				// Will either be set below, or later by Netty
				headers.remove(HttpHeaders.HOST);
				if (preserveHost) {
					String host = request.getHeaders().getFirst(HttpHeaders.HOST);
					headers.add(HttpHeaders.HOST, host);
				}
			}).request(method).uri(url).send((req, nettyOutbound) -> {//url:目标地址
				return nettyOutbound.send(request.getBody()
						.map(dataBuffer -> ((NettyDataBuffer) dataBuffer)
								.getNativeBuffer()));
			}).responseConnection((res, connection) -> {
				// 4.配置response connection
            	// 之后NettyWriteResponseFilter就是靠这个连接来接收response字节流
				exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
				// 把response connection设置为一个属性到exchange
            	// 这个版本已经变成NettyWriteResponseFilter通过response connection拿到响应字节流的
				exchange.getAttributes().put(CLIENT_RESPONSE_CONN_ATTR, connection);
				ServerHttpResponse response = exchange.getResponse();
				// put headers and status so filters can modify the response
				HttpHeaders headers = new HttpHeaders();
				res.responseHeaders().forEach(
						entry -> headers.add(entry.getKey(), entry.getValue()));
				String contentTypeValue = headers.getFirst(HttpHeaders.CONTENT_TYPE);
				if (StringUtils.hasLength(contentTypeValue)) {
					exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR,
							contentTypeValue);
				}
				setResponseStatus(res, response);
				HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
						getHeadersFilters(), headers, exchange, Type.RESPONSE);
				...
				response.getHeaders().putAll(filteredResponseHeaders);

				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));
}
private HttpClient httpClientWithTimeoutFrom(Route route) {
	Integer connectTimeout = (Integer) route.getMetadata().get(CONNECT_TIMEOUT_ATTR);
	if (connectTimeout != null) {
		return this.httpClient.tcpConfiguration((tcpClient) -> tcpClient
				.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout));
	}
	//HttpClientTcpConfig
	return httpClient;
}

4.2、GatewayFilter

需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上。

RequestRateLimiter就是官方定义的默认31种过滤器之一。
1、SpringCloud之Gateway源码解析_第2张图片

5、predicate

时间类型的Predicated(AfterRoutePredicateFactory BeforeRoutePredicateFactory BetweenRoutePredicateFactory),当只有满足特定时间要求的请求会进入到此predicate中,并交由router处理;cookie类型的CookieRoutePredicateFactory,指定的cookie满足正则匹配,才会进入此router;以及host、method、path、querparam、remoteaddr类型的predicate,每一种predicate都会对当前的客户端请求进行判断,是否满足当前的要求,如果满足则交给当前请求处理。
1、SpringCloud之Gateway源码解析_第3张图片

你可能感兴趣的:(spring,cloud,gateway,java)