Back to Javatutorial

SpringCloudGateway源码分析

docs/Spring全家桶/SpringCloud源码分析/SpringCloudGateway源码分析.md

1.0.011.1 KB
Original Source

ѧϰĿ

  1. Gatewayԭ 1 Bean׼ ǰҲôˣǼ spring-cloud-starter-gateway֣һstarter˵ȥspring.factoriesļһЩҪbeanԶװIoCˡ

1. GatewayClassPathWarningAutoConfiguration

@Configuration(proxyBeanMethods = false)
//ǰGatewayAutoConfiguration֮ǰ
@AutoConfigureBefore(GatewayAutoConfiguration.class)
public class GatewayClassPathWarningAutoConfiguration {
	...      
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
	protected static class SpringMvcFoundOnClasspathConfiguration {
		public SpringMvcFoundOnClasspathConfiguration() {
			log.warn(BORDER
					+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "
					+ "Please remove spring-boot-starter-web dependency." + BORDER);
		}

	}
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
	protected static class WebfluxMissingFromClasspathConfiguration {

		public WebfluxMissingFromClasspathConfiguration() {
			log.warn(BORDER + "Spring Webflux is missing from the classpath, "
					+ "which is required for Spring Cloud Gateway at this time. "
					+ "Please add spring-boot-starter-webflux dependency." + BORDER);
		}
	}
}

ܿʵϾͨConditionOnClassConditionOnMissingClass־ӡĹܣClassPath org.springframework.web.servlet.DispatcherServletĻʵһBeanȻӡ־spring-boot-starter-webȻټClassPathǷȷwebfluxûУӡ־spring-boot-starter-webflux

2.GatewayAutoConfiguration

Ϊ̫ͲչʾˣоټȽҪ

  • PropertiesRouteDefinitionLocatorڴļyml/propertiesжȡ·Ϣ
  • RouteDefinitionLocator RouteDefinition תΪ Route
  • RoutePredicateHandlerMapping mvc HandlerMapping GatewayʵֵġƥӦroute
  • GatewayPropertiesymlϢװ GatewayProperties
  • AfterRoutePredicateFactory·ɶԹЩԹʱѾɶӦbeanDzſ yml һ£Ч
  • RetryGatewayFilterFactory Gateway ЩʱѾɶӦbeanDzſ yml һ£Ч
  • GlobalFilterʵࣺȫֹ

3.HttpHandlerAutoConfigurationWebFluxAutoConfiguration࣬GatewayAutoConfiguration֮ʵֱʵHttpHandlerWebFluxConfigBean

2 ִ һнHystrixԭHystrixкҵ߼ͨӦʽɵģʵϣGatewayҲǻͬı̷ͬģGatewayͬSpringMVCҲdzơ

ǰʱ򣬴£

  1. ȱDispatcherHandlerأȻURIн
  2. ȻURIȥHandlerMappingȡҪִеWebHandler
  3. ȻѡһʵHandlerAdapterִ
  4. ִWebHandler gatewayʱе󶼻뵽DispatcherHandlerеhandleһ𿴿
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
    if (this.handlerMappings == null) {
        return createNotFoundError();
    }
    //webFluxӦʽ
    return Flux
        // 1.DZе handlerMapping
        .fromIterable(this.handlerMappings)
        // 2.ȡӦhandlerMapping 糣õ RequestMappingHandlerMappingRoutePredicateHandlerMapping
        .concatMap(mapping -> mapping.getHandler(exchange))
        .next()
        .switchIfEmpty(createNotFoundError())
        // 3.ȡӦöӦĴ
        .flatMap(handler -> invokeHandler(exchange, handler))
        // 4.ش
        .flatMap(result -> handleResult(exchange, result));
}

2.1 getHandler getHandlerGatewayĺ߼ڣgetHandlerлȡӦHandlerMapping

AbstractHandlerMapping.getHandlerԴ

@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
    //һȡ·ɵʵ࣬뵽RoutePredicateHandlerMapping
    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;
    });
}
@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());
    //ѰҲƥ·
    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);
            // webHandler
            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) + "]");
        }
    })));
}

lookupRouteҵymlõе·ɶԹBeforeAfterPathȵȣִapply·ƥ䣬жǷִͨ˳springbootԶʱԼƶ

protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
    // getRoutes ȡеĶԹ
    return this.routeLocator.getRoutes()
        .concatMap(route -> Mono.just(route).filterWhen(r -> {
            exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
            // ȻȡRouteڲpredicate
            //Ȼapply ִжԣжǷͨ
            return r.getPredicate().apply(exchange);
        }).doOnError(e -> logger.error(
                       "Error applying predicate for route: " + route.getId(),
                       e))
                   .onErrorResume(e -> Mono.empty()))
        .next()
        .map(route -> {
            if (logger.isDebugEnabled()) {
                logger.debug("Route matched: " + route.getId());
            }
            validateRoute(route, exchange);
            return route;
        });
}

getRoutes()ͨ RouteDefinitionRouteLocatorļлȡ·ɵģȻҵ·תRoute

@Override
public Flux<Route> getRoutes() {
    // getRouteDefinitions() ļлȡ·
    Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
        // convertToRoute()ҵ·תRoute
        .map(this::convertToRoute);
    ...
}
public class Route implements Ordered {
	private final String id;
	private final URI uri;
	private final int order;
	private final AsyncPredicate<ServerWebExchange> predicate;
	private final List<GatewayFilter> gatewayFilters;
	private final Map<String, Object> metadata;	
    ...
}

2.2 invokeHandler Gatewayһƥ·ɺ󷵻صwebHandler͵ģҲҪҵӦHandlerAdaptorȡӦ invokeHandler(exchange, handler)

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
    if (this.handlerAdapters != null) {
        //ҵеHandlerAdapterȥƥWebFlux
        for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
            if (handlerAdapter.supports(handler)) {
                return handlerAdapter.handle(exchange, handler);
            }
        }
    }
    return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

SimpleHandlerAdapter еhandle

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

webHandler.handleǴйķùglobalFiltersgatewayFilters

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
    // 1\. ·İ󶨹ϵȡӦ·Route
    Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
    List<GatewayFilter> gatewayFilters = route.getFilters();
    // 2\. ռе globalFilters List<GatewayFilter>
    //עʹģʽ
    List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
    // 3\.  gatewayFilters ҲList<GatewayFilter>γһ
    combined.addAll(gatewayFilters);
    // 4\. order
    AnnotationAwareOrderComparator.sort(combined);
    if (logger.isDebugEnabled()) {
        logger.debug("Sorted gatewayFilterFactories: " + combined);
    }
    // 5\. ִйеÿһ
    return new DefaultGatewayFilterChain(combined).filter(exchange);
}

ע⣺װʱǰglobalFiltersgatewayFiltersֹŽList<GatewayFilter>Уôأ

ʵõһ ģʽ

  • globalFiltersȰglobalFiltersתGatewayFilterAdapter GatewayFilterAdapterڲGlobalFilterͬʱҲʵGatewayFilterʹ globalFiltersgatewayFilters GatewayFilterAdapterй棡
  • gatewayFiltersֱӷ뼴ɣ 3 ؾ GatewayĸؾֻҪyml uri: lb://userʵָؾ⣬ײȫֹLoadBalancerClientFilterfilterȥģ

Զ http://localhost:9527/get/3Ϊ9527ΪGatewayĶ˿

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    // 1\. ·İ󶨹ϵ
    // ȡԭʼurlhttp://localhost:9527/get/3
    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);
    }
    addOriginalRequestUrl(exchange, url);
    if (log.isTraceEnabled()) {
        log.trace("LoadBalancerClientFilter url before: " + url);
    }
    // 2\. ͨribbonĸؾ㷨ݷȥnacosEurekaѡһʵ
    // ʵuser url ַhttp://localhost:8080/get/3
    final ServiceInstance instance = choose(exchange);
    if (instance == null) {
        throw NotFoundException.create(properties.isUse404(),
                                       "Unable to find instance for " + url.getHost());
    }
    // 3\. õԭ uri http://localhost:9527/get/3
    URI uri = exchange.getRequest().getURI();
    String overrideScheme = instance.isSecure() ? "https" : "http";
    if (schemePrefix != null) {
        overrideScheme = url.getScheme();
    }
    // 4\. ÷ʵinstanceuri滻ԭuriַ õ µurl
    // µurl: http://localhost:8080/get/3
    URI requestUrl = loadBalancer.reconstructURI(
        new DelegatingServiceInstance(instance, overrideScheme), uri);
    if (log.isTraceEnabled()) {
        log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
    }
    // 5\. ٴμ¼Ĺϵ
    exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
    // 6\. ִйе
    return chain.filter(exchange);
}

ο

https://lijunyi.xyz/docs/SpringCloud/SpringCloud.html#_2-2-x-%E5%88%86%E6%94%AF https://mp.weixin.qq.com/s/2jeovmj77O9Ux96v3A0NtA https://juejin.cn/post/6931922457741770760 https://github.com/D2C-Cai/herring http://c.biancheng.net/springcloud https://github.com/macrozheng/springcloud-learning