Spring Cloud Gateway系列(一):整体流程

GateWay作为Spring Cloud的全新项目,目的是取代旧版本中的Netflix Zuul,从而实现更高的性能,本系列将会以下三个部分:

  1. 整体流程
  2. 全局CORS配置
  3. 动态路由刷新

Gateway接收到来自客户端的请求之后,请求首先进入HttpWebHandlerAdapter 类:

@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
	if (this.forwardedHeaderTransformer != null) {
		request = this.forwardedHeaderTransformer.apply(request);
	}
    //过滤器中使用的ServerWebExchange就是在这里创建的DefaultServerWebExchange
	ServerWebExchange exchange = createExchange(request, response);

	LogFormatUtils.traceDebug(logger, traceOn ->
			exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
						(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
    //getDelegate()返回的是ExceptionHandlingWebHandler
	return getDelegate().handle(exchange)
			.doOnSuccess(aVoid -> logResponse(exchange))
			.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
			.then(Mono.defer(response::setComplete));
}

 ExceptionHandlingWebHandler类的handle(exchange)方法调用其父类WebHandlerDecorator的handle(exchange)方法,最终会调用FilteringWebHandler的hanlde(exchange)方法。

//ExceptionHandlingWebHandler类
@Override
public Mono<Void> handle(ServerWebExchange exchange) {

		Mono<Void> completion;
		try {
            //调用父类WebHandlerDecorator的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;
}

//WebHandlerDecorator类
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
        //调用FilteringWebHandler.handle(exchange)方法
		return this.delegate.handle(exchange);
}

//FilteringWebHandler类
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
		return this.chain.filter(exchange);
}

 然后进入DefaultWebFilterChain的filter(exchange)方法

@Override
public Mono<Void> filter(ServerWebExchange exchange) {
    /*1.先执行所有的 WebFilter 
        特别注意:WebFilter不是Gateway特有的网关全局GlobalFilter和自定义的AbstractGatewayFilterFactory
      2.然后执行DispatcherHandler的handle方法
        DispatcherHandler可类比Spring MVC的DispatcherServlet
        DispatcherHandler的三个属性就很清楚的表明了它的功能
        通过handlerMappings确定具体处理网关请求的handler
        通过handlerAdapters确定具体处理handler的handlerAdapter并处理handler
        最终由resultHandler生成返回结果
        private List<HandlerMapping> handlerMappings;
        private List<HandlerAdapter> handlerAdapters;
        private List<HandlerResultHandler> resultHandlers;
    */
	return Mono.defer(() ->
	this.currentFilter != null && this.next != null ?
			this.currentFilter.filter(exchange, this.next) :
			this.handler.handle(exchange));
}

核心类DispatcherHandler:

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
	if (this.handlerMappings == null) {
		return createNotFoundError();
	}
    /*需要注意的就是Flux的next()方法 
      如果客户端请求的URL与Gateway中通过@RestController自定义的API路径
      和网关路由定义的转发路径都匹配时,handlerMappings会匹配多个handler
      通过next()方法只取出第一个匹配的handler执行下面的调用方法*/      
	return Flux.fromIterable(this.handlerMappings)
			.concatMap(mapping -> mapping.getHandler(exchange))
			.next()
			.switchIfEmpty(createNotFoundError())
			.flatMap(handler -> invokeHandler(exchange, handler))
			.flatMap(result -> handleResult(exchange, result));
}

 mapping.getHandler(exchange)方法会执行AbstractHandlerMapping的getHandler(exchange)方法,我们在配置文件中指定的全局跨域规则就是在这个方法里生效的!

@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
               /*getHandlerInternal方法是一个抽象方法
                 由AbstractHandlerMapping的子类实现该方法
                */
		return getHandlerInternal(exchange).map(handler -> {
			if (logger.isDebugEnabled()) {
				logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
			}
            /* REQUEST_HANDLED_HANDLER是一个函数式接口 exhange->Mono.empty()
               如果客户端请求是跨域请求,就会去读区配置文件
               判断当前请求是否允许跨域         
            */
			if (CorsUtils.isCorsRequest(exchange.getRequest())) {
				CorsConfiguration configA = this.corsConfigurationSource.getCorsConfiguration(exchange);
				CorsConfiguration configB = getCorsConfiguration(handler, exchange);
				CorsConfiguration config = (configA != null ? configA.combine(configB) : configB);
                /*
                  CORS的核心 使用的是Spring5特有的PathPattern
                  这里先给出跨域配置样例,后续会专门分析这个方法
spring.cloud.gateway.globalcors.corsConfigurations.[/*/*/users/*/message_roaming/*].allowedOrigins=*
spring.cloud.gateway.globalcors.corsConfigurations.[/*/*/users/*/message_roaming/*].allowedHeaders=*
spring.cloud.gateway.globalcors.corsConfigurations.[/*/*/users/*/message_roaming/*].allowedMethods=*
spring.cloud.gateway.globalcors.corsConfigurations.[/*/*/users/*/message_roaming/*].allowCredentials=true
spring.cloud.gateway.globalcors.corsConfigurations.[/*/*/users/*/message_roaming/*].maxAge=1728000
                  需要特别注意的就是,如果客户端请求是跨域请求
                  如果存在配置属性与之匹配,就会放行
                  如果不存在,则会拒绝该请求,设置ResponseHeader,返回REQUEST_HANDLED_HANDLER,
                */
				if (!getCorsProcessor().process(config, exchange) ||
						CorsUtils.isPreFlightRequest(exchange.getRequest())) {
					return REQUEST_HANDLED_HANDLER;
				}
			}
			return handler;
		});
}

AbstractHandlerMapping抽象类有很多实现类,只关注用来处理路由转发的RoutePredicateHandlerMapping类。

 RoutePredicateHandlerMapping的getHandlerInternal方法返回FilteringWebHandler类,然后就会返回执行DispatcherHandler的handle方法执行handler -> invokeHandler(exchange, handler)方法

//
private final FilteringWebHandler webHandler;

@Override
	protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
        /*引入spring-boot-actuator组件后,为了安全性考虑,
         可以通过management.server.port指定服务监控端口,
         该端口下的请求URL是不需要经过Predicates校验的
        */
		// 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方法将根据配置文件中指定的predicates断言器和请求路径做匹配
        如果匹配成功就会返回FilteringWebHandler*/
		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);
                    //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) + "]");
					}
				})));
	}

invokeHandler(exchange, handler)方法如下:

	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
		if (this.handlerAdapters != null) {
            /*找到支持FilteringWebHandler的HandlerAdapter
              然后调用FilteringWebHandler的handle方法*/
			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
                /*重点关注SimpleHandlerAdapter
                SimpleHandlerAdapter用于执行gateway过滤器链*/
				if (handlerAdapter.supports(handler)) {
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}

SimpleHandlerAdapter执行的是FilteringWebHandler类的handle方法

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) {
        //FilteringWebHandler类
		WebHandler webHandler = (WebHandler) handler;
		Mono<Void> mono = webHandler.handle(exchange);
		return mono.then(Mono.empty());
	}

}

FilteringWebHandler类的handle方法如下:

@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
        /*Gateway自定义多种过滤器,
          同时我们可以通过实现AbstractGatewayFilterFactory类自定义局部过滤器*/
		List<GatewayFilter> gatewayFilters = route.getFilters();

		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
        //对全局过滤器和配置文件指定的路由局部过滤器统一排序
		// TODO: needed or cached?
		AnnotationAwareOrderComparator.sort(combined);

		if (logger.isDebugEnabled()) {
			logger.debug("Sorted gatewayFilterFactories: " + combined);
		}
        //生成Gateway过滤器链,然后对客户端请求进行处理
		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}

GatewayFilterChain过滤器链中真正执行后端服务调用的Filter是NettyRoutingFilter,有兴趣的同学可以阅读以下。

 由于SimpleHandlerAdapter的handler方法返回的是mono.then(Mono.empty()),暂时没有发现后续的handleResult方法被调用。

此过程大致是Gateway路由转发的整体过程,Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty,在此记录下网关调优相关的Netty的两个核心配置参数:

public final class ReactorNetty {

	// System properties names


	/**
	 * Specifies whether the channel ID will be prepended to the log message when possible.
	 * By default it will be prepended.
	 */
	static final boolean LOG_CHANNEL_INFO =
			Boolean.parseBoolean(System.getProperty("reactor.netty.logChannelInfo", "true"));

	/**
	 * Default worker thread count, fallback to available processor
	 * (but with a minimum value of 4)
	 */
	public static final String IO_WORKER_COUNT = "reactor.netty.ioWorkerCount";
	/**
	 * Default selector thread count, fallback to -1 (no selector thread)
	 */
	public static final String IO_SELECT_COUNT = "reactor.netty.ioSelectCount";
}

(*^__^*)(*^__^*)(*^__^*)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值