Spring Cloud Gateway 系列(二)处理请求流程

北城以北 提交于 2020-04-24 02:14:28

本篇文章主要从源码的角度揭秘Spring Cloud Gateway的加载和怎么处理请求流程。

1.Spring Gateway概述

SpringCloudGateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

2.容器启动过程的简单加载分析

加载的流程主要是spring容器为主,需要大家熟悉spring框架,这里不做过多的分析了。
Spring Cloud Gateway自动装配类在 org.springframework.cloud.gateway.config 包下,我们可以看到四个配置类 :
GatewayAutoConfiguration
GatewayClassPathWarningAutoConfiguration
GatewayLoadBalancerClientAutoConfiguration
GatewayRedisAutoConfiguration
它们的初始化顺序如下图 :

2.1 GatewayClassPathWarningAutoConfiguration

Spring Cloud Gateway 2.x 基于 Spring WebFlux 实现。

org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,用于检查项目是否正确导入 spring-boot-starter-webflux 依赖,而不是错误导入 spring-boot-starter-web 依赖。点击查看源代码

2.2 GatewayLoadBalancerClientAutoConfiguration

org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration ,初始化 LoadBalancerClientFilter ,点击查看源代码

2.3 GatewayRedisAutoConfiguration

org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration ,初始化 RedisRateLimiter 。
RequestRateLimiterGatewayFilterFactory 基于 RedisRateLimiter 实现网关的限流功能

2.4 GatewayAutoConfiguration

org.springframework.cloud.gateway.config.GatewayAutoConfiguration ,Spring Cloud Gateway 核心配置类,初始化如下 :
NettyConfiguration
GlobalFilter
FilteringWebHandler
GatewayProperties
PrefixPathGatewayFilterFactory
RoutePredicateFactory
RouteDefinitionLocator
RouteLocator
RoutePredicateHandlerMapping
GatewayControllerEndpoint

组件关系交互如下图 :

2.5 网关的开启与关闭

从 GatewayAutoConfiguration 上的注解 @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) ,我们可以看出 :

通过 spring.cloud.gateway.enabled 配置网关的开启与关闭。
matchIfMissing = true => 网关默认开启。

2.6 初始化 NettyConfiguration

org.springframework.cloud.gateway.config.NettyConfiguration ,Netty 配置类。代码如下 :

 @Configuration
    @ConditionalOnClass({HttpClient.class})
    protected static class NettyConfiguration {
        protected NettyConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean
        public HttpClient httpClient(@Qualifier("nettyClientOptions") Consumer<? super Builder> options) {
            return HttpClient.create(options);
        }

        @Bean
        public Consumer<? super Builder> nettyClientOptions(HttpClientProperties properties) {
            return (opts) -> {
                Ssl ssl = properties.getSsl();
                if (ssl.isUseInsecureTrustManager()) {
                    opts.sslSupport((sslContextBuilder) -> {
                        sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
                    });
                }

                Pool pool = properties.getPool();
                PoolResources poolResources;
                if (pool.getType() == PoolType.FIXED) {
                    poolResources = PoolResources.fixed(pool.getName(), pool.getMaxConnections(), pool.getAcquireTimeout());
                } else {
                    poolResources = PoolResources.elastic(pool.getName());
                }

                opts.poolResources(poolResources);
                Proxy proxy = properties.getProxy();
                if (StringUtils.hasText(proxy.getHost())) {
                    opts.proxy((typeSpec) -> {
                        reactor.ipc.netty.options.ClientProxyOptions.Builder builder = typeSpec.type(reactor.ipc.netty.options.ClientProxyOptions.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 builder;
                    });
                }

            };
        }

2.7 初始化 GlobalFilter

代码如下:

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

    @Bean
    @ConditionalOnBean({DispatcherHandler.class})
    public ForwardRoutingFilter forwardRoutingFilter(DispatcherHandler dispatcherHandler) {
        return new ForwardRoutingFilter(dispatcherHandler);
    }

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

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

2.8初始化 FilteringWebHandler

当所有 org.springframework.cloud.gateway.filter.GlobalFilter 初始化完成时( 包括上面的 NettyRoutingFilter / NettyWriteResponseFilter ),创建一个类型为 org.springframework.cloud.gateway.handler.FilteringWebHandler 的 Bean 对象,代码如下 :

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

2.9 初始化 GatewayProperties

创建一个类型为 org.springframework.cloud.gateway.config.GatewayProperties 的 Bean 对象,用于加载配置文件配置的 RouteDefinition / FilterDefinition 。代码如下 :

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

3.0 初始化 PrefixPathGatewayFilterFactory

 链接 的【第 288 至 372 行】,创建 org.springframework.cloud.gateway.filter.factory 包下的 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 接口的实现们。

3.1 初始化 RoutePredicateFactory

 链接 的【第 236 至 284 行】,创建 org.springframework.cloud.gateway.handler.predicate 包下的 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 接口的实现们。

3.2初始化 RouteDefinitionLocator

代码如下 :

@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));
    }

3.3 初始化 RouteLocator

代码如下 :

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

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

另外,有如下两种方式实现自定义 RouteLocator :

使用 Routes#locator()#build() 方法,创建 RouteLocator ,例子代码如下 :

@Bean
public RouteLocator customRouteLocator() {
    //@formatter:off
    return Routes.locator()
            .route("test")
                .predicate(host("**.abc.org").and(path("/image/png")))
                .addResponseHeader("X-TestHeader", "foobar")
                .uri("http://httpbin.org:80")
            .route("test2")
                .predicate(path("/image/webp"))
                .add(addResponseHeader("X-AnotherHeader", "baz"))
                .uri("http://httpbin.org:80")
            .build();
    ////@formatter:on
}

使用 RouteLocatorDsl#gateway() 方法,创建 RouteLocator ,该方式使用 Kotlin 实现,例子代码如下 :

@Configuration
class AdditionalRoutes {
    @Bean
    fun additionalRouteLocator(): RouteLocator = gateway {
        route(id = "test-kotlin") {
            uri("http://httpbin.org:80")
            predicate(host("kotlin.abc.org") and path("/image/png"))
            add(addResponseHeader("X-TestHeader", "foobar"))
        }
    }
}

3.4 初始化 RoutePredicateHandlerMapping

创建一个类型为 org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping 的 Bean 对象,用于查找匹配到 Route ,并进行处理。代码如下 :

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

3.5初始化 GatewayWebfluxEndpoint

创建一个类型为 org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint 的 Bean 对象,提供管理网关的 HTTP API ,代码如下 :

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

        @Bean
        @ConditionalOnEnabledEndpoint
        public GatewayControllerEndpoint gatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters, List<GatewayFilterFactory> GatewayFilters, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) {
            return new GatewayControllerEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator);
        }
    }

4. Spring Cloud gateway请求入口分析

不管是Zuul,还是Spring Cloud Gateway还是基于Netty的自研网关,都会把请求进来的Request,或者返回的Response进行包装,转换提取为网关运行的上下文信息,而在Spring Cloud gateway中网关的上下文为ServerWebExchange。

4.1 入口HttpServerRequest和HttpServerResponse转换

Spring Cloud Gateway的请求入口,org.springframework.http.server.reactive.ReactorHttpHandlerAdapter#apply方法

代码来源于spring-web-5.0.4.RELEASE.jar 此方法为Spring Cloud Gateway的请求入口方法,该方法的作用就是把接收到的HttpServerRequest或者最终需要返回的HttpServerResponse,包装转换为ReactorServerHttpRequest和ReactorServerHttpResponse。

4.2 构造Spring Cloud gateway的上下文ServerWebExchange

在org.springframework.web.server.adapter.HttpWebHandlerAdapter的91行,代码如下所示:

createExchange()将ServerHttpRequest ServerHttpResponse构建网关上下文ServerWebExchange。

PS:org.springframework.web.server.handler.WebHandlerDecorator.getDelegate()通过委托的方式获取一系列需要处理的WebHandler.

4.3 进入Filter链

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle方法,即46行,代码如下所示:

4.4 执行Filter链

4.5 Gateway Filter委托为Gloable Filter执行

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!