Gateway源码解析

目录

概况

pom解析

spring.factories解析

GatewayClassPathWarningAutoConfiguration类

GatewayAutoConfiguration类

GatewayHystrixCircuitBreakerAutoConfiguration类

GatewayLoadBalancerClientAutoConfiguration类

GatewayNoLoadBalancerClientAutoConfiguration类

GatewayMetricsAutoConfiguration类

GatewayRedisAutoConfiguration类

GatewayDiscoveryClientAutoConfiguration类

SimpleUrlHandlerMappingGlobalCorsAutoConfiguration类

GatewayReactiveLoadBalancerClientAutoConfiguration类

路由配置加载

1、加载Route对象beans实例化

2、InMemoryRouteDefinitionRepository提供save/delete操作RouteDefinition(路由对象)

3、CompositeRouteDefinitionLocator提供将RouteDefinition加载到RouteDefinitionLocator

4、RouteDefinitionRouteLocator

5、CachingRouteLocator提供由applicatEventPublisther自动刷新对Route缓存

6、图解

调用链路解析

1、调用api接口,由于自定义Filter的order一般很小(如tokenFilter -100之类),请求从经过该类Filter

2、进入DispatcherHandler.handle()

3、进入RoutePredicateHandlerMapping

4、进入FilteringWebHandler根据GatewayFilterChain中Filters列表按order值从小到大,依次执行filters方法调用

4.1、LoadBalancerClientFilter负载均衡

4.2、ForwardRoutingFilter

5、图解

RouteDefinition类

RouteDefinitionRouteLocator类

RoutePredicateHandlerMapping类

LoadBalancerClientFilter类

Exchange 标记 Routed


概况

版本:2.2.4.RELEASE

服务注册由Nacos提供

pom解析

从spring-cloud-gateway pom中可看出其核心依赖包括:

<dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter</artifactId>
      <version>2.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    //core
    //包含:spring-boot-starter/spring-boot-starter-security/spring-boot-autoconfigure-processor/spring-boot-starter-data-redis
    //spring-cloud-starter-netflix-ribbon/spring-cloud-starter-netflix-hystrix...
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-gateway-core</artifactId>
      <version>2.2.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    //webflux
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
      <version>2.3.2.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    //负载均衡
    //包含:spring-cloud-starter/spring-cloud-loadbalancer/spring-boot-starter-cache...
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
      <version>2.2.4.RELEASE</version>
      <scope>compile</scope>
      <optional>true</optional>
    </dependency>
  </dependencies>

spring.factories解析

注意:在3.0.0.RELEASE中,已经GatewayReactiveLoadBalancerClientAutoConfiguration替代GatewayResilience4JCircuitBreakerAutoConfiguration实现ReactiveLoadBalancerClientFilter。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayHystrixCircuitBreakerAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayResilience4JCircuitBreakerAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
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.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor

GatewayClassPathWarningAutoConfiguration类

classPath检测

注意依赖org.springframework.web.servlet.DispatcherServlet

@Configuration(
    proxyBeanMethods = false
)
@AutoConfigureBefore({GatewayAutoConfiguration.class})
public class GatewayClassPathWarningAutoConfiguration {
    ...
    //检测spring-boot-starter-webflux dependency有否存在
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnMissingClass({"org.springframework.web.reactive.DispatcherHandler"})
    protected static class WebfluxMissingFromClasspathConfiguration {
        public WebfluxMissingFromClasspathConfiguration() {
            GatewayClassPathWarningAutoConfiguration.log.warn("\n\n**********************************************************\n\nSpring Webflux is missing from the classpath, which is required for Spring Cloud Gateway at this time. Please add spring-boot-starter-webflux dependency.\n\n**********************************************************\n\n");
        }
    }

    //检测spring-boot-starter-web dependency是否去除
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass(
        name = {"org.springframework.web.servlet.DispatcherServlet"}
    )
    protected static class SpringMvcFoundOnClasspathConfiguration {
        public SpringMvcFoundOnClasspathConfiguration() {
            GatewayClassPathWarningAutoConfiguration.log.warn("\n\n**********************************************************\n\nSpring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. Please remove spring-boot-starter-web dependency.\n\n**********************************************************\n\n");
        }
    }
}

GatewayAutoConfiguration类

核心类

内置各类Filter 与 Factory 实例化

详情见源码注解:

@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@EnableConfigurationProperties
@AutoConfigureBefore({HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class})
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class})
public class GatewayAutoConfiguration {
    //属性对象实例化
    @Bean
    public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) {
        return new RouteLocatorBuilder(context);
    }

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

    //RouteDefinition的存储,RouteDefinition会在后面转换成Route: Map<String, RouteDefinition>
    @Bean
    @ConditionalOnMissingBean({RouteDefinitionRepository.class})
    public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
        return new InMemoryRouteDefinitionRepository();
    }

   //注入所有RouteDefinitionLocator,配置的路由通过子类PropertiesRouteDefinitionLocator来完成的,
    @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);
    }
    
    //RouteDefinitionLocator 作为参数注入到routeDefinitionLocator
    @Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, ConfigurationService configurationService) {
        return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, gatewayFilters, properties, configurationService);
    }

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

    //提供刷新RouteLocator
    @Bean
    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();
    }

    //开始filter实例化
    //forwardedHeader路由
    @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
    public AdaptCachedBodyGlobalFilter adaptCachedBodyGlobalFilter() {
        return new AdaptCachedBodyGlobalFilter();
    }

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

    //基于请求URI创建一个新URI,但使用Route对象的URI属性进行更新。适用于lb:ws://serviceid
    //lb方案从URI中剥离,并放入中以ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR供稍后在过滤器链中使用
    @Bean
    public RouteToRequestUrlFilter routeToRequestUrlFilter() {
        return new RouteToRequestUrlFilter();
    }

    //forward 正向路由
    @Bean
    public ForwardRoutingFilter forwardRoutingFilter(ObjectProvider<DispatcherHandler> dispatcherHandler) {
        return new ForwardRoutingFilter(dispatcherHandler);
    }

   //ForwardPathFilter路由
    @Bean
    public ForwardPathFilter forwardPathFilter() {
        return new ForwardPathFilter();
    }

    @Bean
    public WebSocketService webSocketService(RequestUpgradeStrategy requestUpgradeStrategy) {
        return new HandshakeWebSocketService(requestUpgradeStrategy);
    }

    //websocket路由过滤器
    //routes:
    //  - id: websocket_route
    //    uri: http://localhost:8080  也可使用lb来负载均衡
    //    predicates:
    //    - Path=/websocket/info/**
    @Bean
    public WebsocketRoutingFilter websocketRoutingFilter(WebSocketClient webSocketClient, WebSocketService webSocketService, ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
        return new WebsocketRoutingFilter(webSocketClient, webSocketService, headersFilters);
    }

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

    //各类Factory实例化
    //Route Predicate Factory
    //predicates:
    //   - After=2020-12-18T17:42:47.789-07:00[XXXX]
    @Bean
    public AfterRoutePredicateFactory afterRoutePredicateFactory() {
        return new AfterRoutePredicateFactory();
    }

    //predicates:
    //   - Before=2020-12-18T17:42:47.789-07:00[XXXX]
    @Bean
    public BeforeRoutePredicateFactory beforeRoutePredicateFactory() {
        return new BeforeRoutePredicateFactory();
    }

   //predicates:
    //   - Between=2020-12-18T17:42:47.789-07:00[XXXX],2020-12-19T17:42:47.789-07:00[XXXX]
    @Bean
    public BetweenRoutePredicateFactory betweenRoutePredicateFactory() {
        return new BetweenRoutePredicateFactory();
    }

    //predicates:
    //   - Cookie=chocolate, xxx...
    @Bean
    public CookieRoutePredicateFactory cookieRoutePredicateFactory() {
        return new CookieRoutePredicateFactory();
    }

    //predicates:
    //    - Header=X-Request-Id, \d+
    @Bean
    public HeaderRoutePredicateFactory headerRoutePredicateFactory() {
        return new HeaderRoutePredicateFactory();
    }

    //predicates:
    //   - Host=**.xxx.com,**.xxx.org
    @Bean
    public HostRoutePredicateFactory hostRoutePredicateFactory() {
        return new HostRoutePredicateFactory();
    }
    //predicates:
    //   - Method=GET
    @Bean
    public MethodRoutePredicateFactory methodRoutePredicateFactory() {
        return new MethodRoutePredicateFactory();
    }

    //predicates:
    //   - Path=/foo/{segment},/bar/{segment}
    @Bean
    public PathRoutePredicateFactory pathRoutePredicateFactory() {
        return new PathRoutePredicateFactory();
    }

    //predicates:
    //    - Query=querxxx
    @Bean
    public QueryRoutePredicateFactory queryRoutePredicateFactory() {
        return new QueryRoutePredicateFactory();
    }

    @Bean
    public ReadBodyPredicateFactory readBodyPredicateFactory(ServerCodecConfigurer codecConfigurer) {
        return new ReadBodyPredicateFactory(codecConfigurer.getReaders());
    }
    
    //predicates:
    //    - RemoteAddr=192.168.10.1/24
    @Bean
    public RemoteAddrRoutePredicateFactory remoteAddrRoutePredicateFactory() {
        return new RemoteAddrRoutePredicateFactory();
    }

    //predicates:
   //   - Weight=group1, 2
    @Bean
    @DependsOn({"weightCalculatorWebFilter"})
    public WeightRoutePredicateFactory weightRoutePredicateFactory() {
        return new WeightRoutePredicateFactory();
    }

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

    //GatewayFilter工厂
    //filters:
    //    - AddRequestHeader=X-Request-Foo, Bar
    @Bean
    public AddRequestHeaderGatewayFilterFactory addRequestHeaderGatewayFilterFactory() {
        return new AddRequestHeaderGatewayFilterFactory();
    }
    //filters:
    //    - MapRequestHeader=Bar, X-Request-Foo
    @Bean
    public MapRequestHeaderGatewayFilterFactory mapRequestHeaderGatewayFilterFactory() {
        return new MapRequestHeaderGatewayFilterFactory();
    }
    
    //filters:
    //   - AddRequestParameter=foo, bar
    @Bean
    public AddRequestParameterGatewayFilterFactory addRequestParameterGatewayFilterFactory() {
        return new AddRequestParameterGatewayFilterFactory();
    }
    //filters:
    //  - AddResponseHeader=X-Response-Foo, Bar
    @Bean
    public AddResponseHeaderGatewayFilterFactory addResponseHeaderGatewayFilterFactory() {
        return new AddResponseHeaderGatewayFilterFactory();
    }

    @Bean
    public ModifyRequestBodyGatewayFilterFactory modifyRequestBodyGatewayFilterFactory(ServerCodecConfigurer codecConfigurer) {
        return new ModifyRequestBodyGatewayFilterFactory(codecConfigurer.getReaders());
    }
    //filters:
    //  - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
    @Bean
    public DedupeResponseHeaderGatewayFilterFactory dedupeResponseHeaderGatewayFilterFactory() {
        return new DedupeResponseHeaderGatewayFilterFactory();
    }
    
    //filters:
    //  - PrefixPath=/mypath
    @Bean
    public PrefixPathGatewayFilterFactory prefixPathGatewayFilterFactory() {
        return new PrefixPathGatewayFilterFactory();
    }

    //filters:
    //   - PreserveHostHeader
    @Bean
    public PreserveHostHeaderGatewayFilterFactory preserveHostHeaderGatewayFilterFactory() {
        return new PreserveHostHeaderGatewayFilterFactory();
    }

...
    //RateLimiter实现来确定是否允许继续当前请求
    @Bean(
        name = {"principalNameKeyResolver"}
    )
    @ConditionalOnBean({RateLimiter.class})
    @ConditionalOnMissingBean({KeyResolver.class})
    public PrincipalNameKeyResolver principalNameKeyResolver() {
        return new PrincipalNameKeyResolver();
    }

    @Bean
    @ConditionalOnBean({RateLimiter.class, KeyResolver.class})
    public RequestRateLimiterGatewayFilterFactory requestRateLimiterGatewayFilterFactory(RateLimiter rateLimiter, KeyResolver resolver) {
        return new RequestRateLimiterGatewayFilterFactory(rateLimiter, resolver);
    }
    
    
    //rewrite & set filters
    @Bean
    public RewritePathGatewayFilterFactory rewritePathGatewayFilterFactory() {
        return new RewritePathGatewayFilterFactory();
    }

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

    @Bean
    public SetPathGatewayFilterFactory setPathGatewayFilterFactory() {
        return new SetPathGatewayFilterFactory();
    }
....
  
    @Bean
    public SaveSessionGatewayFilterFactory saveSessionGatewayFilterFactory() {
        return new SaveSessionGatewayFilterFactory();
    }

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

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

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

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

    //hystrix
    //filters:
    // - Hystrix=myCommandName
    //或
    //   filters:          
    //   - name: Hystrix    //定义hystrix
    //      args:
    //        name: fetchIngredients
    //        fallbackUri: forward:/fallback
    //- id: ingredients-fallback   //定义fallback访问
    //   uri: http://localhost:9994
    //   predicates:
    //     - Path=/fallback
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({HystrixObservableCommand.class, RxReactiveStreams.class})
    protected static class HystrixConfiguration {
        protected HystrixConfiguration() {
        }

        @Bean
        public HystrixGatewayFilterFactory hystrixGatewayFilterFactory(ObjectProvider<DispatcherHandler> dispatcherHandler) {
            return new HystrixGatewayFilterFactory(dispatcherHandler);
        }

        @Bean
        @ConditionalOnMissingBean({FallbackHeadersGatewayFilterFactory.class})
        public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
            return new FallbackHeadersGatewayFilterFactory();
        }
    }
    
    //netty filter
    @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 if (pool.getType() == PoolType.FIXED) {
                connectionProvider = ConnectionProvider.fixed(pool.getName(), pool.getMaxConnections(), pool.getAcquireTimeout(), pool.getMaxIdleTime(), pool.getMaxLifeTime());
            } else {
                connectionProvider = ConnectionProvider.elastic(pool.getName(), pool.getMaxIdleTime(), pool.getMaxLifeTime());
            }

            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) -> {
                        Builder builder = proxySpec.type(reactor.netty.tcp.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
        public NettyRoutingFilter routingFilter(HttpClient httpClient, ObjectProvider<List<HttpHeadersFilter>> headersFilters, HttpClientProperties properties) {
            return new NettyRoutingFilter(httpClient, headersFilters, properties);
        }
    
        @Bean
        public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
            return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
        }

        @Bean
        public ReactorNettyWebSocketClient reactorNettyWebSocketClient(HttpClientProperties properties, HttpClient httpClient) {
            ReactorNettyWebSocketClient webSocketClient = new ReactorNettyWebSocketClient(httpClient);
            if (properties.getWebsocket().getMaxFramePayloadLength() != null) {
                webSocketClient.setMaxFramePayloadLength(properties.getWebsocket().getMaxFramePayloadLength());
            }

            webSocketClient.setHandlePing(properties.getWebsocket().isProxyPing());
            return webSocketClient;
        }

        @Bean
        public ReactorNettyRequestUpgradeStrategy reactorNettyRequestUpgradeStrategy(HttpClientProperties httpClientProperties) {
            ReactorNettyRequestUpgradeStrategy requestUpgradeStrategy = new ReactorNettyRequestUpgradeStrategy();
            Websocket websocket = httpClientProperties.getWebsocket();
            PropertyMapper map = PropertyMapper.get();
            websocket.getClass();
            map.from(websocket::getMaxFramePayloadLength).whenNonNull().to(requestUpgradeStrategy::setMaxFramePayloadLength);
            websocket.getClass();
            map.from(websocket::isProxyPing).to(requestUpgradeStrategy::setHandlePing);
            return requestUpgradeStrategy;
        }
    }
}

GatewayHystrixCircuitBreakerAutoConfiguration类

熔断器实例化

      routes:
      - id: test
        uri: lb://test
        predicates:
        - Path=//test/**
       filters:                //定义hystrix circuitbreaker
        - name: CircuitBreaker
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback    //定义fallback访问
        uri: http://localhost:9994
        predicates:
        - Path=/fallback
        filters:
        - name: FallbackHeaders       //fallbackHeader配置
          args:
            executionExceptionTypeHeaderName: Test-Header
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@AutoConfigureAfter({ReactiveHystrixCircuitBreakerAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class, HystrixCircuitBreakerAutoConfiguration.class, ReactiveCircuitBreakerFactory.class, ReactiveHystrixCircuitBreakerFactory.class})
public class GatewayHystrixCircuitBreakerAutoConfiguration {
    ...

    @Bean
    @ConditionalOnBean({ReactiveHystrixCircuitBreakerFactory.class})
    public SpringCloudCircuitBreakerHystrixFilterFactory springCloudCircuitBreakerHystrixFilterFactory(ReactiveHystrixCircuitBreakerFactory reactiveCircuitBreakerFactory, ObjectProvider<DispatcherHandler> dispatcherHandler) {
        return new SpringCloudCircuitBreakerHystrixFilterFactory(reactiveCircuitBreakerFactory, dispatcherHandler);
    }

    @Bean
    @ConditionalOnMissingBean({FallbackHeadersGatewayFilterFactory.class})
    public FallbackHeadersGatewayFilterFactory fallbackHeadersGatewayFilterFactory() {
        return new FallbackHeadersGatewayFilterFactory();
    }
}

GatewayLoadBalancerClientAutoConfiguration类

引入ribbon时的负载均衡实例化

当GatewayLoadBalancerClientAutoConfiguration条件互斥

LoadBalancerClientFilter与ReactiveLoadBalancerClientFilter只会实例化一个

   routes:
      - id: myRoute
        uri: lb://servicetest
        predicates:
        - Path=/servicetest/**
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
@AutoConfigureAfter({RibbonAutoConfiguration.class})
@EnableConfigurationProperties({LoadBalancerProperties.class})
public class GatewayLoadBalancerClientAutoConfiguration {
    public GatewayLoadBalancerClientAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean({LoadBalancerClient.class})
    @ConditionalOnMissingBean({LoadBalancerClientFilter.class, ReactiveLoadBalancerClientFilter.class})
    public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client, LoadBalancerProperties properties) {
        return new LoadBalancerClientFilter(client, properties);
    }
}

GatewayNoLoadBalancerClientAutoConfiguration类

没有引入ribbon时的负载均衡实例化

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnMissingClass({"org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration"})
@ConditionalOnMissingBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerProperties.class})
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class})
public class GatewayNoLoadBalancerClientAutoConfiguration {
    public GatewayNoLoadBalancerClientAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean({LoadBalancerClientFilter.class})
    public GatewayNoLoadBalancerClientAutoConfiguration.NoLoadBalancerClientFilter noLoadBalancerClientFilter(LoadBalancerProperties properties) {
        return new GatewayNoLoadBalancerClientAutoConfiguration.NoLoadBalancerClientFilter(properties.isUse404());
    }

    protected static class NoLoadBalancerClientFilter implements GlobalFilter, Ordered {
        private final boolean use404;

        public NoLoadBalancerClientFilter(boolean use404) {
            this.use404 = use404;
        }

        public int getOrder() {
            return 10100;
        }

        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
            String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
            if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
                throw NotFoundException.create(this.use404, "Unable to find instance for " + url.getHost());
            } else {
                return chain.filter(exchange);
            }
        }
    }
}

GatewayMetricsAutoConfiguration类

整合监控相关,提供监控指标。与actuators配合

url暴露在 /actuator/metrics/gateway.requests 端点中,也可以轻松与 Prometheus 整合,从而创建一个 Grafana dashboard。

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@EnableConfigurationProperties({GatewayMetricsProperties.class})
@AutoConfigureBefore({HttpHandlerAutoConfiguration.class})
@AutoConfigureAfter({MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class, MeterRegistry.class, MetricsAutoConfiguration.class})
public class GatewayMetricsAutoConfiguration {
    ...
    @Bean
    @ConditionalOnBean({MeterRegistry.class})
    @ConditionalOnProperty(
        name = {"spring.cloud.gateway.metrics.enabled"},
        matchIfMissing = true
    )
    public GatewayMetricsFilter gatewayMetricFilter(MeterRegistry meterRegistry, List<GatewayTagsProvider> tagsProviders) {
        return new GatewayMetricsFilter(meterRegistry, tagsProviders);
    }
}

GatewayRedisAutoConfiguration类

与redies结合,可使用到限流等方面:

RedisRateLimiter+request_rate_limiter.lua脚本

@Configuration(
    proxyBeanMethods = false
)
@AutoConfigureAfter({RedisReactiveAutoConfiguration.class})
@AutoConfigureBefore({GatewayAutoConfiguration.class})
@ConditionalOnBean({ReactiveRedisTemplate.class})
@ConditionalOnClass({RedisTemplate.class, DispatcherHandler.class})
class GatewayRedisAutoConfiguration {
    GatewayRedisAutoConfiguration() {
    }

    @Bean
    public RedisScript redisRequestRateLimiterScript() {
        DefaultRedisScript redisScript = new DefaultRedisScript();
        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("META-INF/scripts/request_rate_limiter.lua")));
        redisScript.setResultType(List.class);
        return redisScript;
    }

    @Bean
    @ConditionalOnMissingBean
    public RedisRateLimiter redisRateLimiter(ReactiveStringRedisTemplate redisTemplate, @Qualifier("redisRequestRateLimiterScript") RedisScript<List<Long>> redisScript, ConfigurationService configurationService) {
        return new RedisRateLimiter(redisTemplate, redisScript, configurationService);
    }
}

GatewayDiscoveryClientAutoConfiguration类

spring.cloud.gateway.discovery.locator.enabled:是否与服务发现组件进行结合,通过 serviceId 转发到具体的服务实例。默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。

与eureka\nacos配合使用

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@AutoConfigureBefore({GatewayAutoConfiguration.class})
@AutoConfigureAfter({CompositeDiscoveryClientAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class})
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
    public GatewayDiscoveryClientAutoConfiguration() {
    }

    public static List<PredicateDefinition> initPredicates() {
        ArrayList<PredicateDefinition> definitions = new ArrayList();
        PredicateDefinition predicate = new PredicateDefinition();
        predicate.setName(NameUtils.normalizeRoutePredicateName(PathRoutePredicateFactory.class));
        predicate.addArg("pattern", "'/'+serviceId+'/**'");
        definitions.add(predicate);
        return definitions;
    }

    public static List<FilterDefinition> initFilters() {
        ArrayList<FilterDefinition> definitions = new ArrayList();
        FilterDefinition filter = new FilterDefinition();
        filter.setName(NameUtils.normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
        String regex = "'/' + serviceId + '/(?<remaining>.*)'";
        String replacement = "'/${remaining}'";
        filter.addArg("regexp", regex);
        filter.addArg("replacement", replacement);
        definitions.add(filter);
        return definitions;
    }

    //DiscoveryLocatorProperties实例化
    @Bean
    public DiscoveryLocatorProperties discoveryLocatorProperties() {
        DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
        properties.setPredicates(initPredicates());
        properties.setFilters(initFilters());
        return properties;
    }

    //开启通过服务中心的自动根据 serviceId 创建路由的功能
    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnProperty(
        value = {"spring.cloud.discovery.reactive.enabled"},
        matchIfMissing = true
    )
    public static class ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration {
        public ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration() {
        }

        @Bean
        @ConditionalOnProperty(
            name = {"spring.cloud.gateway.discovery.locator.enabled"}
        )
        public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
            return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
        }
    }
}

SimpleUrlHandlerMappingGlobalCorsAutoConfiguration类

spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping为ture时,支持cors-configurations配置,对CORS请求预检

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({SimpleUrlHandlerMapping.class})
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping"},
    matchIfMissing = false
)
public class SimpleUrlHandlerMappingGlobalCorsAutoConfiguration {
   ...
      //CORS请求预检
    @PostConstruct
    void config() {
        this.simpleUrlHandlerMapping.setCorsConfigurations(this.globalCorsProperties.getCorsConfigurations());
    }
}

GatewayReactiveLoadBalancerClientAutoConfiguration类

ReactiveLoadBalancerClientFilter实例化

LoadBalancerClientFilter与ReactiveLoadBalancerClientFilter只会实例化一个

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({ReactiveLoadBalancer.class, LoadBalancerAutoConfiguration.class, DispatcherHandler.class})
@AutoConfigureBefore({GatewayLoadBalancerClientAutoConfiguration.class})
@AutoConfigureAfter({LoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({LoadBalancerProperties.class})
public class GatewayReactiveLoadBalancerClientAutoConfiguration {
...

    //ReactiveLoadBalancerClientFilter实例化
    @Bean
    @ConditionalOnBean({LoadBalancerClientFactory.class})
    @ConditionalOnMissingBean({ReactiveLoadBalancerClientFilter.class})
    @Conditional({GatewayReactiveLoadBalancerClientAutoConfiguration.OnNoRibbonDefaultCondition.class})
    public ReactiveLoadBalancerClientFilter gatewayLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory, LoadBalancerProperties properties) {
        return new ReactiveLoadBalancerClientFilter(clientFactory, properties);
    }

    private static final class OnNoRibbonDefaultCondition extends AnyNestedCondition {
        private OnNoRibbonDefaultCondition() {
            super(ConfigurationPhase.REGISTER_BEAN);
        }

        @ConditionalOnMissingClass({"org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient"})
        static class RibbonLoadBalancerNotPresent {
            RibbonLoadBalancerNotPresent() {
            }
        }

        @ConditionalOnProperty(
            value = {"spring.cloud.loadbalancer.ribbon.enabled"},
            havingValue = "false"
        )
        static class RibbonNotEnabled {
            RibbonNotEnabled() {
            }
        }
    }
}

 

路由配置加载

1、加载Route对象beans实例化

2、InMemoryRouteDefinitionRepository提供save/delete操作RouteDefinition(路由对象)

3、CompositeRouteDefinitionLocator提供将RouteDefinition加载到RouteDefinitionLocator

4、RouteDefinitionRouteLocator

提供将RouteDefinitionLocator/predicates/gatewayFilterFactories/gatewayProperties/configurationService对象加载到RouteDefinitionRouteLocator对象,并提供获取各对象的方法

5、CachingRouteLocator提供由applicatEventPublisther自动刷新对Route缓存

6、图解

image

调用链路解析

1、调用api接口,由于自定义Filter的order一般很小(如tokenFilter -100之类),请求从经过该类Filter

2、进入DispatcherHandler.handle()

DispathcerHandler适配器转发,把ServerHttpRequest/ServerHttpResponse转换成ServerWebExchange

3、进入RoutePredicateHandlerMapping

因为其order=1。AbstractHandlerMapping类中获取Handler时带参数ServerWebExchange调用RoutePredicateHandlerMapping.getHandlerInternal方法,通过lookupRoute()方法--》lookupRoute(exchange)

在lookupRoute(exchange)中如果匹配从exchange中gatewayPredicateRouteAttr设值为servieid

加入GatewayFilterChain

4、进入FilteringWebHandler根据GatewayFilterChain中Filters列表按order值从小到大,依次执行filters方法调用

其中:

4.1、LoadBalancerClientFilter负载均衡

当进入LoadBalancerClientFilter,由URI为lb:类型,通过this.loadBalancer.choose()(负载均衡LoadBalancerClient实例化)从获取接口服务,其getInstance()有三个实现(TraceFeignContext/SpringClientFactory/NamedContextFactory),当前是从

NamedContextFactory实现getInstance方法,接口服务实例根据serviceid从AnnotationConfigApplicationContext中获取 (说明服务实例已被NacosServer加载到AnnotationConfigApplicationContext)

4.2、ForwardRoutingFilter

最后进入ForwardRoutingFilter,当有forward时,还是通过DispatcherHandler().handle(exchange)到真实的接口服务

5、图解

1、

image.png

image.png

2、RoutePredicateHandlerMapping

image.png

image.png

3、ForwardPathFilter

image.png

 

4、当失败时,交由AbstractHanderMapping转发到当前 接口

image.png

 

RouteDefinition类

@Validated
public class RouteDefinition {
    private String id;
    @NotEmpty
    @Valid
    private List<PredicateDefinition> predicates = new ArrayList();
    @Valid
    private List<FilterDefinition> filters = new ArrayList();
    @NotNull
    private URI uri;
    private Map<String, Object> metadata = new HashMap();
    private int order = 0;

RouteDefinitionRouteLocator类

public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
    public static final String DEFAULT_FILTERS = "defaultFilters";
    protected final Log logger = LogFactory.getLog(this.getClass());
    private final RouteDefinitionLocator routeDefinitionLocator;
    private final ConfigurationService configurationService;
    private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap();
    private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap();
    private final GatewayProperties gatewayProperties;

    public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List<RoutePredicateFactory> predicates, List<GatewayFilterFactory> gatewayFilterFactories, GatewayProperties gatewayProperties, ConfigurationService configurationService) {
        this.routeDefinitionLocator = routeDefinitionLocator;
        this.configurationService = configurationService;
        this.initFactories(predicates);
        gatewayFilterFactories.forEach((factory) -> {
            GatewayFilterFactory var10000 = (GatewayFilterFactory)this.gatewayFilterFactories.put(factory.name(), factory);
        });
        this.gatewayProperties = gatewayProperties;
    }

    ...

    private void initFactories(List<RoutePredicateFactory> predicates) {
        predicates.forEach((factory) -> {
            String key = factory.name();
            if (this.predicates.containsKey(key)) {
                this.logger.warn("A RoutePredicateFactory named " + key + " already exists, class: " + this.predicates.get(key) + ". It will be overwritten.");
            }

            this.predicates.put(key, factory);
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Loaded RoutePredicateFactory [" + key + "]");
            }

        });
    }

    public Flux<Route> getRoutes() {
        Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);
        if (!this.gatewayProperties.isFailOnRouteDefinitionError()) {
            routes = routes.onErrorContinue((error, obj) -> {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("RouteDefinition id " + ((RouteDefinition)obj).getId() + " will be ignored. Definition has invalid configs, " + error.getMessage());
                }

            });
        }

        return routes.map((route) -> {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("RouteDefinition matched: " + route.getId());
            }

            return route;
        });
    }

    private Route convertToRoute(RouteDefinition routeDefinition) {
        AsyncPredicate<ServerWebExchange> predicate = this.combinePredicates(routeDefinition);
        List<GatewayFilter> gatewayFilters = this.getFilters(routeDefinition);
        return ((AsyncBuilder)Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters)).build();
    }

    List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
        ArrayList<GatewayFilter> ordered = new ArrayList(filterDefinitions.size());

        for(int i = 0; i < filterDefinitions.size(); ++i) {
            FilterDefinition definition = (FilterDefinition)filterDefinitions.get(i);
            GatewayFilterFactory factory = (GatewayFilterFactory)this.gatewayFilterFactories.get(definition.getName());
            if (factory == null) {
                throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
            }

            if (this.logger.isDebugEnabled()) {
                this.logger.debug("RouteDefinition " + id + " applying filter " + definition.getArgs() + " to " + definition.getName());
            }

            Object configuration = this.configurationService.with(factory).name(definition.getName()).properties(definition.getArgs()).eventFunction((bound, properties) -> {
                return new FilterArgsEvent(this, id, (Map)properties);
            }).bind();
            if (configuration instanceof HasRouteId) {
                HasRouteId hasRouteId = (HasRouteId)configuration;
                hasRouteId.setRouteId(id);
            }

            GatewayFilter gatewayFilter = factory.apply(configuration);
            if (gatewayFilter instanceof Ordered) {
                ordered.add(gatewayFilter);
            } else {
                ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
            }
        }

        return ordered;
    }

    private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
        List<GatewayFilter> filters = new ArrayList();
        if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
            filters.addAll(this.loadGatewayFilters("defaultFilters", new ArrayList(this.gatewayProperties.getDefaultFilters())));
        }

        if (!routeDefinition.getFilters().isEmpty()) {
            filters.addAll(this.loadGatewayFilters(routeDefinition.getId(), new ArrayList(routeDefinition.getFilters())));
        }

        AnnotationAwareOrderComparator.sort(filters);
        return filters;
    }

    private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
        List<PredicateDefinition> predicates = routeDefinition.getPredicates();
        AsyncPredicate<ServerWebExchange> predicate = this.lookup(routeDefinition, (PredicateDefinition)predicates.get(0));

        AsyncPredicate found;
        for(Iterator var4 = predicates.subList(1, predicates.size()).iterator(); var4.hasNext(); predicate = predicate.and(found)) {
            PredicateDefinition andPredicate = (PredicateDefinition)var4.next();
            found = this.lookup(routeDefinition, andPredicate);
        }

        return predicate;
    }

    private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
        RoutePredicateFactory<Object> factory = (RoutePredicateFactory)this.predicates.get(predicate.getName());
        if (factory == null) {
            throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("RouteDefinition " + route.getId() + " applying " + predicate.getArgs() + " to " + predicate.getName());
            }

            Object config = ((ConfigurableBuilder)((ConfigurableBuilder)((ConfigurableBuilder)this.configurationService.with(factory).name(predicate.getName())).properties(predicate.getArgs())).eventFunction((bound, properties) -> {
                return new PredicateArgsEvent(this, route.getId(), properties);
            })).bind();
            return factory.applyAsync(config);
        }
    }
}

RoutePredicateHandlerMapping类

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    private final FilteringWebHandler webHandler;
    private final RouteLocator routeLocator;
    private final Integer managementPort;
    private final RoutePredicateHandlerMapping.ManagementPortType managementPortType;

    public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
        this.webHandler = webHandler;
        this.routeLocator = routeLocator;
        this.managementPort = getPortProperty(environment, "management.server.");
        this.managementPortType = this.getManagementPortType(environment);
        this.setOrder(1);
        this.setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
    }
...

    protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
        if (this.managementPortType == RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT && this.managementPort != null && exchange.getRequest().getURI().getPort() == this.managementPort) {
            return Mono.empty();
        } else {
            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);
                return Mono.just(this.webHandler);
            }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("No RouteDefinition found for [" + this.getExchangeDesc(exchange) + "]");
                }

            })));
        }
    }

    protected CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) {
        return super.getCorsConfiguration(handler, exchange);
    }

    protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
        return this.routeLocator.getRoutes().concatMap((route) -> {
            return Mono.just(route).filterWhen((r) -> {
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                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;
        });
    }

}

LoadBalancerClientFilter类

该类后续不推介使用,在3.0.0版本中已由ReactiveLoadBalancerClientFilter替代

public class LoadBalancerClientFilter implements GlobalFilter, Ordered {
    public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;
    private static final Log log = LogFactory.getLog(LoadBalancerClientFilter.class);
    protected final LoadBalancerClient loadBalancer;
    private LoadBalancerProperties properties;

   
    public int getOrder() {
        return 10100;
    }

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = (URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = (String)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("lb".equals(url.getScheme()) || "lb".equals(schemePrefix))) {
            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            if (log.isTraceEnabled()) {
                log.trace("LoadBalancerClientFilter url before: " + url);
            }

            ServiceInstance instance = this.choose(exchange);
            if (instance == null) {
                throw NotFoundException.create(this.properties.isUse404(), "Unable to find instance for " + url.getHost());
            } else {
                URI uri = exchange.getRequest().getURI();
                String overrideScheme = instance.isSecure() ? "https" : "http";
                if (schemePrefix != null) {
                    overrideScheme = url.getScheme();
                }

                URI requestUrl = this.loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri);
                if (log.isTraceEnabled()) {
                    log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                }

                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                return chain.filter(exchange);
            }
        } else {
            return chain.filter(exchange);
        }
    }

    protected ServiceInstance choose(ServerWebExchange exchange) {
        return this.loadBalancer.choose(((URI)exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR)).getHost());
    }
}

Exchange 标记 Routed

通过以上所有内置的全局过滤器后,不同协议的请求会由不同的过滤器转发到下游。

当一个请求走完整条过滤器链后,负责转发请求到下游的那个过滤器会在 exchange 中添加一个 gatewayAlreadyRouted 属性,从而将 exchange 标记为 routed(已路由)。一旦请求被标记为 routed ,其他路由过滤器将不会再次路由该请求,而是直接跳过。负责添加这个gatewayAlreadyRouted 属性的过滤器就是最终负责转发请求的过滤器:

  • http、https请求会由NettyRoutingFilter或WebClientHttpRoutingFilter添加这个属性
  • forward请求会由ForwardRoutingFilter添加这个属性
  • websocket请求会由WebsocketRoutingFilter添加这个属性
  • 这些过滤器调用了以下方法将 exchange 标记为 routed ,或检查 exchange 是否是 routed:
  • ServerWebExchangeUtils.isAlreadyRouted:检查exchange是否为routed状态
  • ServerWebExchangeUtils.setAlreadyRouted:将exchange设置为routed状态

总结,当Gateway通过 gatewayAlreadyRouted 属性表示这个请求已经转发过了,而无需其他过滤器重复路由,从而防止重复的路由转发。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Cloud Gateway 是一个基于 Spring Framework 5、Spring Boot 2 和 Project Reactor 的 API 网关服务。它提供了一种简单而强大的方法来路由和过滤请求,并将它们转发到底层的微服务。对于理解 Spring Cloud Gateway 的工作原理和深入研究其源代码是非常有用的。 首先,通过源码可以发现 Spring Cloud Gateway 主要由三个核心模块组成:路由模块、过滤器模块和事件模块。路由模块负责根据定义的路由规则将请求转发到特定的目标地址。过滤器模块负责在请求的不同阶段执行一系列的过滤器来处理请求。事件模块则用于处理与路由和过滤器相关的异步事件。 源码中的路由模块使用了 Reactive Streams API 中的 Flux 和 Mono 类来处理异步操作。它利用 RouterFunction 和 HandlerFunction 来定义路由和处理请求的方法,并通过 RoutePredicateFactory 来解析和匹配路由规则。在路由模块中,使用了 Netty 库来实现底层的网络通信和请求转发。 通过源码分析过滤器模块,可以发现 Spring Cloud Gateway 的过滤器分为全局过滤器和自定义过滤器两种类型。全局过滤器在请求的全局范围内应用,并且可以用于添加一些全局的处理逻辑。自定义过滤器则允许开发者根据需要添加自定义的过滤逻辑。过滤器的执行顺序可以通过 Order 注解来控制,以满足不同过滤器的执行顺序需求。 事件模块在源码中使用了 Reactor 提供的 EventProcessor 来处理与路由和过滤器相关的事件。它使用了 Reactor 的 FluxSink 和 MonoSink 来创建异步事件源,并通过事件处理器将事件发送给注册的监听器。通过查看事件模块的源码,可以更加深入地了解 Spring Cloud Gateway 是如何处理与路由和过滤器相关的事件的。 总结而言,通过源码分析 Spring Cloud Gateway,我们可以更好地了解其内部的工作原理和实现细节。这对于开发者来说是非常有用的,因为它可以帮助我们更好地使用和扩展 Spring Cloud Gateway 来满足不同的场景需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值