Gateway WebFlux 核心请求流程源码分析

前言

上一篇简单介绍了 Spring Cloud Gateway 的一些基本概念及简单应用,本篇我们将开始深入剖析 Spring Cloud Gateway 源码。

Gateway 的自动配置

使用过 Spring Boot 的都知道,在引入一个新的组件的时候,该组件一般都会有一个 AutoConfiguration 的自动配置类来完成该组件的配置,Gateway 的源码我们就从 GatewayAutoConfiguration 自动配置类来做为入口,我们先来看下 spring-cloud-gateway-server 的 META-INF 下的 spring.factories 中有那些配置类,如下:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayResilience4JCircuitBreakerAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration,\
org.springframework.cloud.gateway.config.SimpleUrlHandlerMappingGlobalCorsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayReactiveOAuth2AutoConfiguration

org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor

果然,我们在 META-INF 下的 spring.factories 中 看到了 GatewayAutoConfiguration。

GatewayAutoConfiguration 源码解析

从 GatewayAutoConfiguration 的源码中我们可以知道该类的主要作用就是初始化各种 Bean 对象,将这些 Bean 对象注入 Spring IOC 容器中,源码如下:

  1. GatewayAutoConfiguration 类上的注解解释:

    • @ConditionalOnProperty:spring.cloud.gateway.enabled配置项必须为true,自动配置才生效。
    • @AutoConfigureBefore:在自动装配 GatewayAutoConfiguration 类之前,必须存在 HttpHandlerAutoConfiguration 和 WebFluxAutoConfiguration 配置类。
    • @AutoConfigureAfter:在自动装配 GatewayAutoConfiguration 类之前,必须存在 GatewayReactiveLoadBalancerClientAutoConfiguration 和 GatewayClassPathWarningAutoConfiguration 自动配置类。
    • @ConditionalOnClass:必须要有 DispatcherHandler 类的时候才自动装配 GatewayAutoConfiguration 类。
  2. 这里简单的列举几个 Bean 对象进行解释:

    • RouteLocatorBuilder:路由构建器,它允许你以编程方式来定义路由规则。
    • PropertiesRouteDefinitionLocator:从配置文件( 例如 YML / Properties ) 读取路由配置。
    • RouteDefinitionLocator:负责读取路由配置,RouteDefinitionLocator 接口有四种实现。
    • RouteLocator :路由定位器,是一个顶级接口,该接口有三个实现类。
    • ForwardRoutingFilter:全局转发过滤器,负责将请求转发到本地 URI。
    • FilteringWebHandler:获取的路由的 GatewayFilter 数组,创建 GatewayFilterChain, 处理过滤器逻辑。
    • RoutePredicateHandlerMapping:用于路由匹配,有点类似 Spring MVC 的HandlerMapping。
    • GatewayProperties:读取 YML / Properties 文件中的各种 Gateway 配置信息,例如路由、限流、过滤器等。
    • ForwardPathFilter:解析路径并且将路径转发。
    • BeforeRoutePredicateFactory:基于Datetime类型的断言工厂,接收一个日期参数,判断请求日期是否早于指定日期(还有一系列的断言工厂不在一一举例)。
    • AddRequestHeaderGatewayFilterFactory:过滤器工厂,添加指定请求 Header 为指定值(还有一系列的过滤器工厂不在一一举例)。
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@EnableConfigurationProperties
@AutoConfigureBefore({HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class})
@AutoConfigureAfter({GatewayReactiveLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class})
public class GatewayAutoConfiguration {
    public GatewayAutoConfiguration() {
    }

    @Bean
    public StringToZonedDateTimeConverter stringToZonedDateTimeConverter() {
        return new StringToZonedDateTimeConverter();
    }

    @Bean
    public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {
        return new RouteLocatorBuilder(context);
    }

    @Bean
    @ConditionalOnMissingBean
    public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
        return new PropertiesRouteDefinitionLocator(properties);
    }

    @Bean
    @ConditionalOnMissingBean({RouteDefinitionRepository.class})
    public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
        return new InMemoryRouteDefinitionRepository();
    }

    @Bean
    @Primary
    public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
        return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
    }

    @Bean
    public ConfigurationService gatewayConfigurationService(BeanFactory beanFactory, @Qualifier("webFluxConversionService") ObjectProvider<ConversionService> conversionService, ObjectProvider<Validator> validator) {
        return new ConfigurationService(beanFactory, conversionService, validator);
    }

    @Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, ConfigurationService configurationService) {
        return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, gatewayFilters, properties, configurationService);
    }

    @Bean
    @Primary
    @ConditionalOnMissingBean(
        name = {"cachedCompositeRouteLocator"}
    )
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
        return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }

    @Bean
    @ConditionalOnClass(
        name = {"org.springframework.cloud.client.discovery.event.HeartbeatMonitor"}
    )
    public RouteRefreshListener routeRefreshListener(ApplicationEventPublisher publisher) {
        return new RouteRefreshListener(publisher);
    }

    @Bean
    public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
        return new FilteringWebHandler(globalFilters);
    }

    @Bean
    public GlobalCorsProperties globalCorsProperties() {
        return new GlobalCorsProperties();
    }

    @Bean
    public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
        return new RoutePredicateHandlerMapping(webHandler, routeLocator, globalCorsProperties, environment);
    }

    @Bean
    public GatewayProperties gatewayProperties() {
        return new GatewayProperties();
    }

    @Bean
    public SecureHeadersProperties secureHeadersProperties() {
        return new SecureHeadersProperties();
    }

    @Bean
    @ConditionalOnProperty(
        name = {"spring.cloud.gateway.forwarded.enabled"},
        matchIfMissing = true
    )
    public ForwardedHeadersFilter forwardedHeadersFilter() {
        return new ForwardedHeadersFilter();
    }

    @Bean
    public RemoveHopByHopHeadersFilter removeHopByHopHeadersFilter() {
        return new RemoveHopByHopHeadersFilter();
    }

    @Bean
    @ConditionalOnProperty(
        name = {"spring.cloud.gateway.x-forwarded.enabled"},
        matchIfMissing = true
    )
    public XForwardedHeadersFilter xForwardedHeadersFilter() {
        return new XForwardedHeadersFilter();
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter
    public AdaptCachedBodyGlobalFilter adaptCachedBodyGlobalFilter() {
        return new AdaptCachedBodyGlobalFilter();
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter
    public RemoveCachedBodyFilter removeCachedBodyFilter() {
        return new RemoveCachedBodyFilter();
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter
    public RouteToRequestUrlFilter routeToRequestUrlFilter() {
        return new RouteToRequestUrlFilter();
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter
    public ForwardRoutingFilter forwardRoutingFilter(ObjectProvider<DispatcherHandler> dispatcherHandler) {
        return new ForwardRoutingFilter(dispatcherHandler);
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter
    public ForwardPathFilter forwardPathFilter() {
        return new ForwardPathFilter();
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter(WebsocketRoutingFilter.class)
    public WebSocketService webSocketService(RequestUpgradeStrategy requestUpgradeStrategy) {
        return new HandshakeWebSocketService(requestUpgradeStrategy);
    }

    @Bean
    @ConditionalOnEnabledGlobalFilter
    public WebsocketRoutingFilter websocketRoutingFilter(WebSocketClient webSocketClient, WebSocketService webSocketService, ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
        return new WebsocketRoutingFilter(webSocketClient, webSocketService, headersFilters);
    }

    @Bean
    @ConditionalOnEnabledPredicate(WeightRoutePredicateFactory.class)
    public WeightCalculatorWebFilter weightCalculatorWebFilter(ConfigurationService configurationService, ObjectProvider<RouteLocator> routeLocator) {
        return new WeightCalculatorWebFilter(routeLocator, configurationService);
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public AfterRoutePredicateFactory afterRoutePredicateFactory() {
        return new AfterRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public BeforeRoutePredicateFactory beforeRoutePredicateFactory() {
        return new BeforeRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public BetweenRoutePredicateFactory betweenRoutePredicateFactory() {
        return new BetweenRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public CookieRoutePredicateFactory cookieRoutePredicateFactory() {
        return new CookieRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public HeaderRoutePredicateFactory headerRoutePredicateFactory() {
        return new HeaderRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public HostRoutePredicateFactory hostRoutePredicateFactory() {
        return new HostRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public MethodRoutePredicateFactory methodRoutePredicateFactory() {
        return new MethodRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public PathRoutePredicateFactory pathRoutePredicateFactory() {
        return new PathRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public QueryRoutePredicateFactory queryRoutePredicateFactory() {
        return new QueryRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public ReadBodyRoutePredicateFactory readBodyPredicateFactory(ServerCodecConfigurer codecConfigurer) {
        return new ReadBodyRoutePredicateFactory(codecConfigurer.getReaders());
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public RemoteAddrRoutePredicateFactory remoteAddrRoutePredicateFactory() {
        return new RemoteAddrRoutePredicateFactory();
    }

    @Bean
    @DependsOn({"weightCalculatorWebFilter"})
    @ConditionalOnEnabledPredicate
    public WeightRoutePredicateFactory weightRoutePredicateFactory() {
        return new WeightRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledPredicate
    public CloudFoundryRouteServiceRoutePredicateFactory cloudFoundryRouteServiceRoutePredicateFactory() {
        return new CloudFoundryRouteServiceRoutePredicateFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public AddRequestHeaderGatewayFilterFactory addRequestHeaderGatewayFilterFactory() {
        return new AddRequestHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public MapRequestHeaderGatewayFilterFactory mapRequestHeaderGatewayFilterFactory() {
        return new MapRequestHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public AddRequestParameterGatewayFilterFactory addRequestParameterGatewayFilterFactory() {
        return new AddRequestParameterGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public AddResponseHeaderGatewayFilterFactory addResponseHeaderGatewayFilterFactory() {
        return new AddResponseHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public ModifyRequestBodyGatewayFilterFactory modifyRequestBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer) {
        return new ModifyRequestBodyGatewayFilterFactory(codecConfigurer.getReaders());
    }

    @Bean
    @ConditionalOnEnabledFilter
    public DedupeResponseHeaderGatewayFilterFactory dedupeResponseHeaderGatewayFilterFactory() {
        return new DedupeResponseHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public ModifyResponseBodyGatewayFilterFactory modifyResponseBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer, Set<MessageBodyDecoder> bodyDecoders, Set<MessageBodyEncoder> bodyEncoders) {
        return new ModifyResponseBodyGatewayFilterFactory(codecConfigurer.getReaders(), bodyDecoders, bodyEncoders);
    }

    @Bean
    @ConditionalOnEnabledFilter
    public PrefixPathGatewayFilterFactory prefixPathGatewayFilterFactory() {
        return new PrefixPathGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public PreserveHostHeaderGatewayFilterFactory preserveHostHeaderGatewayFilterFactory() {
        return new PreserveHostHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RedirectToGatewayFilterFactory redirectToGatewayFilterFactory() {
        return new RedirectToGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RemoveRequestHeaderGatewayFilterFactory removeRequestHeaderGatewayFilterFactory() {
        return new RemoveRequestHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RemoveRequestParameterGatewayFilterFactory removeRequestParameterGatewayFilterFactory() {
        return new RemoveRequestParameterGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RemoveResponseHeaderGatewayFilterFactory removeResponseHeaderGatewayFilterFactory() {
        return new RemoveResponseHeaderGatewayFilterFactory();
    }

    @Bean(
        name = {"principalNameKeyResolver"}
    )
    @ConditionalOnBean({RateLimiter.class})
    @ConditionalOnMissingBean({KeyResolver.class})
    @ConditionalOnEnabledFilter(RequestRateLimiterGatewayFilterFactory.class)
    public PrincipalNameKeyResolver principalNameKeyResolver() {
        return new PrincipalNameKeyResolver();
    }

    @Bean
    @ConditionalOnBean({RateLimiter.class, KeyResolver.class})
    @ConditionalOnEnabledFilter
    public RequestRateLimiterGatewayFilterFactory requestRateLimiterGatewayFilterFactory(RateLimiter rateLimiter, KeyResolver resolver) {
        return new RequestRateLimiterGatewayFilterFactory(rateLimiter, resolver);
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RewritePathGatewayFilterFactory rewritePathGatewayFilterFactory() {
        return new RewritePathGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RetryGatewayFilterFactory retryGatewayFilterFactory() {
        return new RetryGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SetPathGatewayFilterFactory setPathGatewayFilterFactory() {
        return new SetPathGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SecureHeadersGatewayFilterFactory secureHeadersGatewayFilterFactory(SecureHeadersProperties properties) {
        return new SecureHeadersGatewayFilterFactory(properties);
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SetRequestHeaderGatewayFilterFactory setRequestHeaderGatewayFilterFactory() {
        return new SetRequestHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SetRequestHostHeaderGatewayFilterFactory setRequestHostHeaderGatewayFilterFactory() {
        return new SetRequestHostHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SetResponseHeaderGatewayFilterFactory setResponseHeaderGatewayFilterFactory() {
        return new SetResponseHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RewriteResponseHeaderGatewayFilterFactory rewriteResponseHeaderGatewayFilterFactory() {
        return new RewriteResponseHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RewriteLocationResponseHeaderGatewayFilterFactory rewriteLocationResponseHeaderGatewayFilterFactory() {
        return new RewriteLocationResponseHeaderGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SetStatusGatewayFilterFactory setStatusGatewayFilterFactory() {
        return new SetStatusGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public SaveSessionGatewayFilterFactory saveSessionGatewayFilterFactory() {
        return new SaveSessionGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public StripPrefixGatewayFilterFactory stripPrefixGatewayFilterFactory() {
        return new StripPrefixGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RequestHeaderToRequestUriGatewayFilterFactory requestHeaderToRequestUriGatewayFilterFactory() {
        return new RequestHeaderToRequestUriGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RequestSizeGatewayFilterFactory requestSizeGatewayFilterFactory() {
        return new RequestSizeGatewayFilterFactory();
    }

    @Bean
    @ConditionalOnEnabledFilter
    public RequestHeaderSizeGatewayFilterFactory requestHeaderSizeGatewayFilterFactory() {
        return new RequestHeaderSizeGatewayFilterFactory();
    }

    @Bean
    public GzipMessageBodyResolver gzipMessageBodyResolver() {
        return new GzipMessageBodyResolver();
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnProperty(
        name = {"spring.cloud.gateway.enabled"},
        matchIfMissing = true
    )
    @ConditionalOnClass({OAuth2AuthorizedClient.class, SecurityWebFilterChain.class, SecurityProperties.class})
    @ConditionalOnEnabledFilter(TokenRelayGatewayFilterFactory.class)
    protected static class TokenRelayConfiguration {
        protected TokenRelayConfiguration() {
        }

        @Bean
        public TokenRelayGatewayFilterFactory tokenRelayGatewayFilterFactory(ObjectProvider<ReactiveOAuth2AuthorizedClientManager> clientManager) {
            return new TokenRelayGatewayFilterFactory(clientManager);
        }
    }

    private static class OnVerboseDisabledCondition extends NoneNestedConditions {
        OnVerboseDisabledCondition() {
            super(ConfigurationPhase.REGISTER_BEAN);
        }

        @ConditionalOnProperty(
            name = {"spring.cloud.gateway.actuator.verbose.enabled"},
            matchIfMissing = true
        )
        static class VerboseDisabled {
            VerboseDisabled() {
            }
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({Health.class})
    protected static class GatewayActuatorConfiguration {
        protected GatewayActuatorConfiguration() {
        }

        @Bean
        @ConditionalOnProperty(
            name = {"spring.cloud.gateway.actuator.verbose.enabled"},
            matchIfMissing = true
        )
        @ConditionalOnAvailableEndpoint
        public GatewayControllerEndpoint gatewayControllerEndpoint(List<GlobalFilter> globalFilters, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> routePredicates, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator, RouteDefinitionLocator routeDefinitionLocator) {
            return new GatewayControllerEndpoint(globalFilters, gatewayFilters, routePredicates, routeDefinitionWriter, routeLocator, routeDefinitionLocator);
        }

        @Bean
        @Conditional({GatewayAutoConfiguration.OnVerboseDisabledCondition.class})
        @ConditionalOnAvailableEndpoint
        public GatewayLegacyControllerEndpoint gatewayLegacyControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> routePredicates, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) {
            return new GatewayLegacyControllerEndpoint(routeDefinitionLocator, globalFilters, gatewayFilters, routePredicates, routeDefinitionWriter, routeLocator);
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({HttpClient.class})
    protected static class NettyConfiguration {
        protected final Log logger = LogFactory.getLog(this.getClass());

        protected NettyConfiguration() {
        }

        @Bean
        @ConditionalOnProperty(
            name = {"spring.cloud.gateway.httpserver.wiretap"}
        )
        public NettyWebServerFactoryCustomizer nettyServerWiretapCustomizer(Environment environment, ServerProperties serverProperties) {
            return new NettyWebServerFactoryCustomizer(environment, serverProperties) {
                public void customize(NettyReactiveWebServerFactory factory) {
                    factory.addServerCustomizers(new NettyServerCustomizer[]{(httpServer) -> {
                        return httpServer.wiretap(true);
                    }});
                    super.customize(factory);
                }
            };
        }

        @Bean
        @ConditionalOnMissingBean
        public HttpClient gatewayHttpClient(HttpClientProperties properties, List<HttpClientCustomizer> customizers) {
            Pool pool = properties.getPool();
            ConnectionProvider connectionProvider;
            if (pool.getType() == PoolType.DISABLED) {
                connectionProvider = ConnectionProvider.newConnection();
            } else {
                Builder builder;
                if (pool.getType() == PoolType.FIXED) {
                    builder = (Builder)((Builder)((Builder)ConnectionProvider.builder(pool.getName()).maxConnections(pool.getMaxConnections())).pendingAcquireMaxCount(-1)).pendingAcquireTimeout(Duration.ofMillis(pool.getAcquireTimeout()));
                    if (pool.getMaxIdleTime() != null) {
                        builder.maxIdleTime(pool.getMaxIdleTime());
                    }

                    if (pool.getMaxLifeTime() != null) {
                        builder.maxLifeTime(pool.getMaxLifeTime());
                    }

                    connectionProvider = builder.build();
                } else {
                    builder = (Builder)((Builder)((Builder)ConnectionProvider.builder(pool.getName()).maxConnections(2147483647)).pendingAcquireTimeout(Duration.ofMillis(0L))).pendingAcquireMaxCount(-1);
                    if (pool.getMaxIdleTime() != null) {
                        builder.maxIdleTime(pool.getMaxIdleTime());
                    }

                    if (pool.getMaxLifeTime() != null) {
                        builder.maxLifeTime(pool.getMaxLifeTime());
                    }

                    connectionProvider = builder.build();
                }
            }

            HttpClient httpClient = HttpClient.create(connectionProvider).httpResponseDecoder((spec) -> {
                if (properties.getMaxHeaderSize() != null) {
                    spec.maxHeaderSize((int)properties.getMaxHeaderSize().toBytes());
                }

                if (properties.getMaxInitialLineLength() != null) {
                    spec.maxInitialLineLength((int)properties.getMaxInitialLineLength().toBytes());
                }

                return spec;
            }).tcpConfiguration((tcpClient) -> {
                if (properties.getConnectTimeout() != null) {
                    tcpClient = tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, properties.getConnectTimeout());
                }

                Proxy proxy = properties.getProxy();
                if (StringUtils.hasText(proxy.getHost())) {
                    tcpClient = tcpClient.proxy((proxySpec) -> {
                        reactor.netty.transport.ProxyProvider.Builder builder = proxySpec.type(reactor.netty.transport.ProxyProvider.Proxy.HTTP).host(proxy.getHost());
                        PropertyMapper map = PropertyMapper.get();
                        proxy.getClass();
                        map.from(proxy::getPort).whenNonNull().to(builder::port);
                        proxy.getClass();
                        map.from(proxy::getUsername).whenHasText().to(builder::username);
                        proxy.getClass();
                        map.from(proxy::getPassword).whenHasText().to((password) -> {
                            builder.password((s) -> {
                                return password;
                            });
                        });
                        proxy.getClass();
                        map.from(proxy::getNonProxyHostsPattern).whenHasText().to(builder::nonProxyHosts);
                    });
                }

                return tcpClient;
            });
            Ssl ssl = properties.getSsl();
            if (ssl.getKeyStore() != null && ssl.getKeyStore().length() > 0 || ssl.getTrustedX509CertificatesForTrustManager().length > 0 || ssl.isUseInsecureTrustManager()) {
                httpClient = httpClient.secure((sslContextSpec) -> {
                    SslContextBuilder sslContextBuilder = SslContextBuilder.forClient();
                    X509Certificate[] trustedX509Certificates = ssl.getTrustedX509CertificatesForTrustManager();
                    if (trustedX509Certificates.length > 0) {
                        sslContextBuilder = sslContextBuilder.trustManager(trustedX509Certificates);
                    } else if (ssl.isUseInsecureTrustManager()) {
                        sslContextBuilder = sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
                    }

                    try {
                        sslContextBuilder = sslContextBuilder.keyManager(ssl.getKeyManagerFactory());
                    } catch (Exception var6) {
                        this.logger.error(var6);
                    }

                    sslContextSpec.sslContext(sslContextBuilder).defaultConfiguration(ssl.getDefaultConfigurationType()).handshakeTimeout(ssl.getHandshakeTimeout()).closeNotifyFlushTimeout(ssl.getCloseNotifyFlushTimeout()).closeNotifyReadTimeout(ssl.getCloseNotifyReadTimeout());
                });
            }

            if (properties.isWiretap()) {
                httpClient = httpClient.wiretap(true);
            }

            if (!CollectionUtils.isEmpty(customizers)) {
                customizers.sort(AnnotationAwareOrderComparator.INSTANCE);

                HttpClientCustomizer customizer;
                for(Iterator var7 = customizers.iterator(); var7.hasNext(); httpClient = customizer.customize(httpClient)) {
                    customizer = (HttpClientCustomizer)var7.next();
                }
            }

            return httpClient;
        }

        @Bean
        public HttpClientProperties httpClientProperties() {
            return new HttpClientProperties();
        }

        @Bean
        @ConditionalOnEnabledGlobalFilter
        public NettyRoutingFilter routingFilter(HttpClient httpClient, ObjectProvider<List<HttpHeadersFilter>> headersFilters, HttpClientProperties properties) {
            return new NettyRoutingFilter(httpClient, headersFilters, properties);
        }

        @Bean
        @ConditionalOnEnabledGlobalFilter(NettyRoutingFilter.class)
        public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
            return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
        }

        @Bean
        @ConditionalOnEnabledGlobalFilter(WebsocketRoutingFilter.class)
        public ReactorNettyWebSocketClient reactorNettyWebSocketClient(HttpClientProperties properties, HttpClient httpClient) {
            reactor.netty.http.client.WebsocketClientSpec.Builder builder = (reactor.netty.http.client.WebsocketClientSpec.Builder)WebsocketClientSpec.builder().handlePing(properties.getWebsocket().isProxyPing());
            if (properties.getWebsocket().getMaxFramePayloadLength() != null) {
                builder.maxFramePayloadLength(properties.getWebsocket().getMaxFramePayloadLength());
            }

            return new ReactorNettyWebSocketClient(httpClient, builder);
        }

        @Bean
        @ConditionalOnEnabledGlobalFilter(WebsocketRoutingFilter.class)
        public ReactorNettyRequestUpgradeStrategy reactorNettyRequestUpgradeStrategy(HttpClientProperties httpClientProperties) {
            reactor.netty.http.server.WebsocketServerSpec.Builder builder = WebsocketServerSpec.builder();
            Websocket websocket = httpClientProperties.getWebsocket();
            PropertyMapper map = PropertyMapper.get();
            websocket.getClass();
            map.from(websocket::getMaxFramePayloadLength).whenNonNull().to(builder::maxFramePayloadLength);
            websocket.getClass();
            map.from(websocket::isProxyPing).to(builder::handlePing);
            return new ReactorNettyRequestUpgradeStrategy(builder);
        }
    }
}

纵观 GatewayAutoConfiguration 类初始化的 Bean 中有一个 RoutePredicateHandlerMapping 类,有点类似 Spring MVC 的HandlerMapping 的作用,而在装配 GatewayAutoConfiguration 类之前必须要有 DispatcherHandler ,我们知道 Spring MVC 的核心组件就是 DispatcherServlet,看起来很相似,根据学习 Spring MVC 的经验,我们是否可以把 DispatcherHandler 做为 Gateway 源码分析的入口呢?

Gateway WebFux 的核心请求流程分析

我们知道 Gateway 采用的是 WebFlux 的响应式编程,处理请求的流程和 Spring MVC 很相似,我们从 DispatcherHandler#handle 方法开始分析。

DispatcherHandler#handle 方法源码解析

DispatcherHandler#handle 是 Gateway 处理请求的核心方法,主要逻辑如下:

  • handlerMappings 为空判断,如果为空直接返回未找到错误。
  • 判断请求是常规请求还是跨域中的预检请求,分别做出不同的处理,我们重点关注常规请求。
  • 对于常规请求,会遍历所有的 handlerMappings 获取 Handler,然后执行 Handler,处理结果集返回,我们重点关注获取 Hanler 和执行 Handler。
//org.springframework.web.reactive.DispatcherHandler#handle
public Mono<Void> handle(ServerWebExchange exchange) {
	//handlerMappings 为空判断
	if (this.handlerMappings == null) {
		//handlerMappings 为空 创建未找到错误
		return this.createNotFoundError();
	} else {
		//CorsUtils.isPreFlightRequest(exchange.getRequest()) 是否是跨域中的预检请求
		//this.handlePreFlight(exchange) 是跨域的预检请求
		//Flux.fromIterable(this.handlerMappings) 常规请求
		return CorsUtils.isPreFlightRequest(exchange.getRequest()) ? this.handlePreFlight(exchange) : 
		//遍历所有的 handlerMappings 获取 Handler
		Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
			return mapping.getHandler(exchange);
		}).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
			//执行 handler
			return this.invokeHandler(exchange, handler);
		}).flatMap((result) -> {
			//结果集处理
			return this.handleResult(exchange, result);
		});
	}
}

AbstractHandlerMapping#getHandler 方法源码解析

AbstractHandlerMapping#getHandler 方法是 Gateway 获取 Hanler 的方法,自身没有什么逻辑,主要是调用了 RoutePredicateHandlerMapping#getHandlerInternal 方法。

//org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
public Mono<Object> getHandler(ServerWebExchange exchange) {
	//调用的是 RoutePredicateHandlerMapping#getHandlerInternal 方法
	return this.getHandlerInternal(exchange).map((handler) -> {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
		}
		//这里是一些跨域的处理
		ServerHttpRequest request = exchange.getRequest();
		if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
			CorsConfiguration config = this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null;
			CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, exchange);
			config = config != null ? config.combine(handlerConfig) : handlerConfig;
			if (config != null) {
				config.validateAllowCredentials();
			}

			if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
				return NO_OP_HANDLER;
			}
		}

		return handler;
	});
}

RoutePredicateHandlerMapping#getHandlerInternal 方法源码解析

RoutePredicateHandlerMapping#getHandlerInternal 方法最终返回了一个 FilteringWebHandler(FilteringWebHandler 中有一个 GatewayFilter 数组,这里返回的其实就是一系列的 GatewayFilter ),方法中会调用 RoutePredicateHandlerMapping#lookupRoute 进行路由匹配。

//org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
	//管理端口和服务端口不一致 不处理
	if (this.managementPortType == RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT && this.managementPort != null && exchange.getRequest().getURI().getPort() == this.managementPort) {
		return Mono.empty();
	} else {
		//给请求设置 gatewayHandlerMapper 的值为  RoutePredicateHandlerMapping  就是设置路由断言处理器映射器
		exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getSimpleName());
		//查找我们在 配置文件中配置的服务路由信息  会匹配当前请求的的路由
		return this.lookupRoute(exchange).flatMap((r) -> {
			//移除网关断言路由属性
			exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Mapping [" + this.getExchangeDesc(exchange) + "] to " + r);
			}
			//设置网关路由
			exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
			//返回 Route 的处理器 FilteringWebHandler 
			return Mono.just(this.webHandler);
		}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
			//移除网关断言路由属性
			exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
			//没有找到 RouteDefinition
			if (this.logger.isTraceEnabled()) {
				this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
			}

		})));
	}
}

FilteringWebHandler 中的 GatewayFilter:

在这里插入图片描述

RoutePredicateHandlerMapping#lookupRoute 方法源码解析

RoutePredicateHandlerMapping#lookupRoute 方法主要功能就是使用路由定位器 RouteLocator 进行断言列表的路由匹配,匹配到当前请求的路由返回,断言匹配失败直接返回空。

//org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
	//routeLocator 路由定位器读取服务中的路由信息
	return this.routeLocator.getRoutes().concatMap((route) -> {
		return Mono.just(route).filterWhen((r) -> {
			//设置路由断言属性
			exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
			//逐个匹配断言配置  获取 路由 Route
			return (Publisher)r.getPredicate().apply(exchange);
		}).doOnError((e) -> {
			this.logger.error("Error applying predicate for route: " + route.getId(), e);
		}).onErrorResume((e) -> {
			//断言匹配失败 返回空
			return Mono.empty();
		});
	}).next().map((route) -> {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Route matched: " + route.getId());
		}
		//路由校验 是空方法 可以自己扩展
		this.validateRoute(route, exchange);
		return route;
	});
}


Route 属性如下:

在这里插入图片描述

DispatcherHandler#invokeHandler 方法源码解析

DispatcherHandler#invokeHandler 方法的主要作用是找到 handler 的处理器适配器,然后去调用 SimpleHandlerAdapter#handle 方法。

//org.springframework.web.reactive.DispatcherHandler#invokeHandler
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
	//status 判断 如果是 403 则直接返回
	if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) {
		return Mono.empty();
	} else {
		//处理器适配器为空判断
		if (this.handlerAdapters != null) {
			//迭代遍历处理器适配器
			Iterator var3 = this.handlerAdapters.iterator();

			while(var3.hasNext()) {
				HandlerAdapter handlerAdapter = (HandlerAdapter)var3.next();
				if (handlerAdapter.supports(handler)) {
					//执行 handler
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		//返回 No HandlerAdapter errror
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}
}

SimpleHandlerAdapter#handle 方法源码解析

SimpleHandlerAdapter#handle 方法调用了 FilteringWebHandler#handle 方法。

//org.springframework.web.reactive.result.SimpleHandlerAdapter#handle
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
	//强转为  WebHandler
	WebHandler webHandler = (WebHandler)handler;
	//调用 FilteringWebHandler#handle 方法
	Mono<Void> mono = webHandler.handle(exchange);
	return mono.then(Mono.empty());
}

FilteringWebHandler#handle 方法源码解析

FilteringWebHandler#handle 主要是对 Rute 和 WebHandler 中的过滤器进行合并排序,然后调用 DefaultGatewayFilterChain#filter 方法执行过滤器逻辑。

//org.springframework.cloud.gateway.handler.FilteringWebHandler#handle
public Mono<Void> handle(ServerWebExchange exchange) {
	//获取 Route 前面有设置进去
	Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
	//从路由中获取 过滤器  路由中也可能没有过滤器
	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);
	}
	//执行过滤器链
	return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);
}

DefaultGatewayFilterChain#filter 方法源码解析

DefaultGatewayFilterChain#filter 方法就是遍历所有过滤器,执行过滤器的过滤逻辑了,,,。

//org.springframework.cloud.gateway.handler.FilteringWebHandler.DefaultGatewayFilterChain#filter
public Mono<Void> filter(ServerWebExchange exchange) {
	//遍历执行过滤器
	return Mono.defer(() -> {
		if (this.index < this.filters.size()) {
			//获取过滤器
			GatewayFilter filter = (GatewayFilter)this.filters.get(this.index);
			//过滤器链
			FilteringWebHandler.DefaultGatewayFilterChain chain = new FilteringWebHandler.DefaultGatewayFilterChain(this, this.index + 1);
			//执行过滤器逻辑
			return filter.filter(exchange, chain);
		} else {
			return Mono.empty();
		}
	});
}

本次请求需要执行的过滤器如下:

在这里插入图片描述

总结:

  1. Gateway 处理请求和 Sping MVC 非常像,分别使用了 DispatcherHandler、HandlerMapping、HandlerAdapter、Handler,熟悉 Spring MVC 的朋友都会感觉这些组件特熟悉。
  2. Gateway 处理请求的流程大致就是:请求到达 --> 匹配路由 --> 执行断言 --> 返回 FilteringWebHandler(实现了 WebHandler 接口)–>执行过滤器 --> 到达目标服务 --> 处理结果返回(这是一个简易版的流程),通过这个流程我们可以知道断言是在过滤器之前执行的,同时也可以看出 Gateway 的主要核心就是路由(Route)断言(Predicates)过滤器(Filters)。

如有不正确的地方请各位指出纠正。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值