前言
上一篇简单介绍了 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 容器中,源码如下:
-
GatewayAutoConfiguration 类上的注解解释:
- @ConditionalOnProperty:spring.cloud.gateway.enabled配置项必须为true,自动配置才生效。
- @AutoConfigureBefore:在自动装配 GatewayAutoConfiguration 类之前,必须存在 HttpHandlerAutoConfiguration 和 WebFluxAutoConfiguration 配置类。
- @AutoConfigureAfter:在自动装配 GatewayAutoConfiguration 类之前,必须存在 GatewayReactiveLoadBalancerClientAutoConfiguration 和 GatewayClassPathWarningAutoConfiguration 自动配置类。
- @ConditionalOnClass:必须要有 DispatcherHandler 类的时候才自动装配 GatewayAutoConfiguration 类。
-
这里简单的列举几个 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();
}
});
}
本次请求需要执行的过滤器如下:
总结:
- Gateway 处理请求和 Sping MVC 非常像,分别使用了 DispatcherHandler、HandlerMapping、HandlerAdapter、Handler,熟悉 Spring MVC 的朋友都会感觉这些组件特熟悉。
- Gateway 处理请求的流程大致就是:请求到达 --> 匹配路由 --> 执行断言 --> 返回 FilteringWebHandler(实现了 WebHandler 接口)–>执行过滤器 --> 到达目标服务 --> 处理结果返回(这是一个简易版的流程),通过这个流程我们可以知道断言是在过滤器之前执行的,同时也可以看出 Gateway 的主要核心就是路由(Route)断言(Predicates)过滤器(Filters)。
如有不正确的地方请各位指出纠正。