SpringBoot Gateway源码讲解

背景:

在微服务架构中,通常一个系统会被拆分为多个微服务,面对这么多微服务客户端应该如何去调用呢?如果没有其他更优方法,我们只能记录每个微服务对应的地址,分别去调用,但是这样会有很多的问题和潜在因素。

客户端多次请求不同的微服务,会增加客户端代码和配置的复杂性,维护成本比价高。

认证复杂,每个微服务可能存在不同的认证方式,客户端去调用,要去适配不同的认证,

存在跨域的请求,调用链有一定的相对复杂性(防火墙 / 浏览器不友好的协议)。

难以重构,随着项目的迭代,可能需要重新划分微服务

为了解决上面的问题,微服务引入了 网关 的概念,网关为微服务架构的系统提供简单、有效且统一的API路由管理,作为系统的统一入口,提供内部服务的路由中转,给客户端提供统一的服务,可以实现一些和业务没有耦合的公用逻辑,主要功能包含认证、鉴权、路由转发、安全策略、防刷、流量控制、监控日志等

在这里插入图片描述

网关对比

Zuul 1.0 : Netflix开源的网关,使用Java开发,基于Servlet架构构建,便于二次开发。因为基于Servlet内部延迟严重,并发场景不友好,一个线程只能处理一次连接请求。

Zuul 2.0 : 采用Netty实现异步非阻塞编程模型,一个CPU一个线程,能够处理所有的请求和响应,请求响应的生命周期通过事件和回调进行处理,减少线程数量,开销较小
在这里插入图片描述
GateWay : 是Spring Cloud的一个全新的API网关项目,替换Zuul开发的网关服务,基于Spring5.0 + SpringBoot2.0 + WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能高于Zuul

Nginx+lua : 性能要比上面的强很多,使用Nginx的反向代码和负载均衡实现对API服务器的负载均衡以及高可用,lua作为一款脚本语言,可以编写一些简单的逻辑,但是无法嵌入到微服务架构中

Kong : 基于OpenResty(Nginx + Lua模块)编写的高可用、易扩展的,性能高效且稳定,支持多个可用插件(限流、鉴权)等,开箱即可用,只支持HTTP协议,且二次开发扩展难,缺乏更易用的管理和配置方式

GateWay
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-starter

Spring Cloud Gateway 是Spring Cloud的一个全新的API网关项目,目的是为了替换掉Zuul1,它基于Spring5.0 + SpringBoot2.0 + WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能于Zuul,官测试,Spring Cloud GateWay是Zuul的1.6倍 ,旨在为微服务架构提供种简单有效的统的API路由管理式。

可以与Spring Cloud Discovery Client(如Eureka)、Ribbon、Hystrix等组件配合使用,实现路由转发、负载均衡、熔断、鉴权、路径重写、志监控等

Gateway还内置了限流过滤器,实现了限流的功能。

设计优雅,容易拓展

基本概念

**路由(Route)**是GateWay中最基本的组件之一,表示一个具体的路由信息载体,主要由下面几个部分组成:

id:路由唯一标识,区别于其他的route

url: 路由指向的目的地URL,客户端请求最终被转发到的微服务

order: 用于多个Route之间的排序,数值越小越靠前,匹配优先级越高

predicate:断言的作用是进行条件判断,只有断言为true,才执行路由

filter: 过滤器用于修改请求和响应信息

核心流程

在这里插入图片描述

源码时序图

在这里插入图片描述

源码讲解

请求进来先被HttpWebHandlerAdapter拦截到


	public HttpWebHandlerAdapter(WebHandler delegate) {
		//此处会执行 this.delegate = delegate;, delegate 为 DispatcherHandler
		super(delegate);
	}
	
	@Override
	public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
		if (this.forwardedHeaderTransformer != null) {
			request = this.forwardedHeaderTransformer.apply(request);
		}
		//封装为DefaultServerWebExchange对象
		ServerWebExchange exchange = createExchange(request, response);

		LogFormatUtils.traceDebug(logger, traceOn ->
				exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
						(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
		//执行到此出,为reactor编程模式
		return getDelegate().handle(exchange)
				.doOnSuccess(aVoid -> logResponse(exchange))
				.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
				.then(Mono.defer(response::setComplete));
	}

我们看下reactor编程模式的这几个方法

1、getDelegate()

	public WebHandler getDelegate() {
		//返回DispatcherHandler实例
		return this.delegate;
	}

2、handle(exchange)

	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		//执行该方法
		//	Flux.fromIterable(this.handlerMappings) 将handlerMappings转化为 Flux
		//1、concatMap中调用mapping.getHandler
		//2、调用next获取匹配的一个Mono
		//3、flatMap中调用invokeHandler方法
		//4、flatMap调用handleResult方法
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}

2.1、mapping.getHandler
org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler

	@Override
	public Mono<Object> getHandler(ServerWebExchange exchange) {
		//1、调用getHandlerInternal,从配置的多个Route中获取匹配的
		return getHandlerInternal(exchange).map(handler -> {
			if (logger.isDebugEnabled()) {
				logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
			}
			ServerHttpRequest request = exchange.getRequest();
			if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
				CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
				CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
				config = (config != null ? config.combine(handlerConfig) : handlerConfig);
				if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
					return REQUEST_HANDLED_HANDLER;
				}
			}
			return handler;
		});
	}

2.1.1 getHandlerInternal
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal

	@Override
	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());
		//1、调用lookupRoute获取合适的Route
		//	统一返回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) + "]");
					}
				})));
	}

2.1.1.1 lookupRoute
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute

	protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
		//1、this.routeLocator.getRoutes()拿到定义的所有的route信息
		//2、Mono.just(route).filterWhen(return r.getPredicate().apply(exchange)) 通过route的断言判断 route是否符合
		//3、返回route
		return this.routeLocator.getRoutes()
				// individually filter routes so that filterWhen error delaying is not a
				// problem
				.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);
				})
						// instead of immediately stopping main flux due to error, log and
						// swallow it
						.doOnError(e -> logger.error(
								"Error applying predicate for route: " + route.getId(),
								e))
						.onErrorResume(e -> Mono.empty()))
				// .defaultIfEmpty() put a static Route not found
				// or .switchIfEmpty()
				// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
				.next()
				// TODO: error handling
				.map(route -> {
					if (logger.isDebugEnabled()) {
						logger.debug("Route matched: " + route.getId());
					}
					validateRoute(route, exchange);
					return route;
				});
	}

2.2、invokeHandler方法调用

	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
				//org.springframework.web.reactive.result.SimpleHandlerAdapter#supports
				//判断是否WebHandler.class
				if (handlerAdapter.supports(handler)) {
					//org.springframework.web.reactive.result.SimpleHandlerAdapter#handle
					//1、方法内部调用FilteringWebHandler的handle方法
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}

2.2.1、handlerAdapter.handle(exchange, handler)

	@Override
	public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
		WebHandler webHandler = (WebHandler) handler;
		//调用FilteringWebHandler#handle方法
		Mono<Void> mono = webHandler.handle(exchange);
		//返回mono
		return mono.then(Mono.empty());
	}

2.2.1、FilteringWebHandler#handle
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle

	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		//从exchange获取到匹配上的route
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		//获取route定义的过滤器
		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);
		}
		//形成责任链模式 依次调用filter方法
		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}

参考文档SpringCloud GateWay 万字详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值