本文章简要对SpringCloudGateway的源码进行分析。
目的让读者能大致了解到Gateway的执行流程,

前序

源码阅读前的建议:
1.了解过Spring&SpringBoot源码(非必需)。
2.了解过Reactor框架的基础(非必需)。

简介

网关的作用在这里就不赘述了,下面这个图(官网上的)描述了网关的大致执行流程原理,现在看着肯定很抽象,本文阅读完后再看这张图你绝对会很清晰。
看图可知道几个重要的部分:

  • Gateway Handler Mapping
  • Gateway Web Handler
  • Filter

    使用Gateway时需要加入的依赖:
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

一段简单的路由配置信息:

- id: web-consumer
  uri: lb://web-consumer
  predicates:   // 谓词
    - Path=/consumer/**
    - Method=GET,POST
  filters:   // 过滤器
    - StripPrefix=1

同样的套路,与Spring Boot整合肯定会有个 xxxAutoConfiguration的自动配置类:

GatewayAutoConfiguration:网关的自动配置类。

GatewayProperties:网关的参数配置类。

springcloudgateway源码解析 spring gateway源码解析_ide


但是仅凭上面的配置类我们是不好源码切入请求的执行的流程,所以我们需要关注Web Flux,一个和spring Mvc作用差不多的框架,Web Flux是用Reactor框架编写并且基于Netty实现的响应式编程,spring Mvc是命令式编程

Web Flux和Spring Mvc很像也有着几大组件:

  • DispatcherHandler
  • HandlerMapping
  • HandlerAdapter
  • Handler

了解过Spring Mvc的源码,就会感觉上面的东西会很熟悉,没错,都差不多。
这下源码切入点就找到了 DispatcherHandler

DispatcherHandler:核心处理请求方法

public class DispatcherHandler implements WebHandler, ApplicationContextAware {
	// 注入进来的 HandlerMapping  HandlerAdapter
	@Nullable
	private List<HandlerMapping> handlerMappings;
	@Nullable
	private List<HandlerAdapter> handlerAdapters;
	@Nullable
	private List<HandlerResultHandler> resultHandlers;
	
	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		return Flux.fromIterable(this.handlerMappings)
				// 根据 HandlerMapping 获取 Handler
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				// 执行找到的 Handler
				.flatMap(handler -> invokeHandler(exchange, handler))
				// 结果处理 返回
				.flatMap(result -> handleResult(exchange, result));
}

下面我们来仔细分析这几步过程。

1.mapping.getHandler(exchange)

这个方法会返回一个 Handler

@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
	// getHandlerInternal() 这个方法有多个实现
	// 网关实现的mapping类是 RoutePredicateHandlerMapping
	return getHandlerInternal(exchange).map(handler -> {
		ServerHttpRequest request = exchange.getRequest();
		// ...
		return handler;
	});
}

// RoutePredicateHandlerMapping#getHandlerInternal

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {

	private final FilteringWebHandler webHandler;
	
	@Override
	protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
		exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
		// lookupRoute方法 是查找 Route,Route就是我们在配置文件里面配置的一个个的服务路由信息
		// 这个方法会找到匹配当前请求的 Route
		return lookupRoute(exchange)
				.flatMap((Function<Route, Mono<?>>) r -> {
					exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
					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);
				})));
	}
}

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
	// routeLocator 是路由加载器,会读取配置文件中的服务路由信息。
	return this.routeLocator.getRoutes()
			.concatMap(route -> Mono.just(route).filterWhen(r -> {
				exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
				// 核心是这一句 r.getPredicate().apply(exchange) 
				// 逐个执行这个这个路由下面配置的谓词列表
				return r.getPredicate().apply(exchange);
			})
			.onErrorResume(e -> Mono.empty()))
			.next()
			.map(route -> {
				validateRoute(route, exchange);
				return route;
			});
}

HandlerMappingRoutePredicateHandlerMapping是GateWay实现的类,从类名字都可以看出这个是用来处理路由上面的谓词的。
RouteLocator:是加载配置中的路由配置,关于配置加载的分析下一篇在进行分析。

上面这部分可以看出:
请求到来 —》匹配路由—〉执行路由谓词 —》返回 Handler
路由谓词就类似断言一样执行失败后整个请求就结束了,后续配置的filter都不会被执行,从这也可以看出:
predicates 优先于filters

2.invokeHandler(exchange, handler)
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
	if (this.handlerAdapters != null) {
		for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
			// 找到符合 handler 的 handlerAdapter
			if (handlerAdapter.supports(handler)) {
			// 执行 handler
				return handlerAdapter.handle(exchange, handler);
			}
		}
	}
	return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

上面可以看出我们返回的handler是FilteringWebHandler

springcloudgateway源码解析 spring gateway源码解析_spring_02


而他对应的适配器是:SimpleHandlerAdapter

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;
		// 	执行 handler 的 webHandler.handle()方法。
		Mono<Void> mono = webHandler.handle(exchange);
		return mono.then(Mono.empty());
	}
}

所以我们重点关注一下FilteringWebHandler的handle()方法即可。
FilteringWebHandler 的注入是在 GatewayAutoConfiguration 中的。

@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
	// 加载了我们自定义的 GlobalFilter
	return new FilteringWebHandler(globalFilters);
}

public class FilteringWebHandler implements WebHandler {

	private final List<GatewayFilter> globalFilters;

	public FilteringWebHandler(List<GlobalFilter> globalFilters) {
		// 会把 GlobalFilter 统一包装成 GatewayFilter
		this.globalFilters = loadFilters(globalFilters);
	}

	private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
		return filters.stream().map(filter -> {
			GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
			// 排序
			if (filter instanceof Ordered) {
				int order = ((Ordered) filter).getOrder();
				return new OrderedGatewayFilter(gatewayFilter, order);
			}
			return gatewayFilter;
		}).collect(Collectors.toList());
	}

	/**
	* 过滤链的核心处理方法
	**/
	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		// 获取 匹配当前请求的 Route
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		// 配置中当前路由中指定的 Filters
		List<GatewayFilter> gatewayFilters = route.getFilters();
		// 内置的filter + 指定的 filter
		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
		AnnotationAwareOrderComparator.sort(combined);
		// 执行 filters 链
		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}
}

这次请求需要执行的过滤链:

springcloudgateway源码解析 spring gateway源码解析_spring boot_03


DefaultGatewayFilterChain这个类的功能就是组织了整条链的执行

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;
		}

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

以上就是大致的请求执行流程,其中有几个内置链是我们需要了解一下的执行过程的:

1.LoadBalancerClientFilter

该Filter功能就是:利用Ribbon的负载均衡选出一个Server。

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
	String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
	if (url == null
			|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
		return chain.filter(exchange);
	}
	// preserve the original url
	addOriginalRequestUrl(exchange, url);
	
	// 核心:负载均衡 执行内置的 Rule(默认是轮训Rule) 选出一个Server
	// ServiceInstance 中有下游服务的IP,端口等等信息
	// 思考:服务的实例是从注册中心拉取的,何时拉取的呢? 更新策略是什么呢?
	final ServiceInstance instance = choose(exchange);

	URI uri = exchange.getRequest().getURI();

	String overrideScheme = instance.isSecure() ? "https" : "http";
	if (schemePrefix != null) {
		overrideScheme = url.getScheme();
	}
	// 这句也是比较核心:完成了URL替换
	// 我们访问是直接访问的网关,这个地方会替换 URL 替换成下游的访问地址
	// http://127.0.0.1:8888/web/index --》http://127.0.0.1:8901/web/index
	URI requestUrl = loadBalancer.reconstructURI(
			new DelegatingServiceInstance(instance, overrideScheme), uri);
	// GATEWAY_REQUEST_URL_ATTR 真实要访问的 接口地址
	exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
	return chain.filter(exchange);
}
2.NettyRoutingFilter

该Filter功能就是:请求下游服务接口返回。

@Override
@SuppressWarnings("Duplicates")
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());
	
	Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
	// 核心:请求转发给下游
	Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
			.headers(headers -> {
				headers.add(httpHeaders);
				headers.remove(HttpHeaders.HOST);
				// send 把组装的数据用 http 形式请求下游服务的接口
			}).request(method).uri(url).send((req, nettyOutbound) -> {
				return nettyOutbound.send(request.getBody().map(this::getByteBuf));
			}).responseConnection((res, connection) -> {

				exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
				exchange.getAttributes().put(CLIENT_RESPONSE_CONN_ATTR, connection);
				ServerHttpResponse response = exchange.getResponse();
				HttpHeaders headers = new HttpHeaders();
				res.responseHeaders().forEach(
						entry -> headers.add(entry.getKey(), entry.getValue()));
				// res 是请求接口返回的数据
				setResponseStatus(res, response);

				HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
						getHeadersFilters(), headers, exchange, Type.RESPONSE);

				exchange.getAttributes().put(CLIENT_RESPONSE_HEADER_NAMES,
						filteredResponseHeaders.keySet());

				response.getHeaders().putAll(filteredResponseHeaders);
				// 返回结果
				return Mono.just(res);
			});
	return responseFlux.then(chain.filter(exchange));
}

其他链的执行过程,感兴趣的可以自行了解。

来幅图大致总结一下流程:

springcloudgateway源码解析 spring gateway源码解析_List_04


总体来看还是比较简单的,没有特别复杂的流程,了解了这个大致流程,如果要扩展网关的功能,大致知道切入点在哪里,然后再做进一步的深究。