Spring Cloud Gateway 源码剖析之配置初始化

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
传统型负载均衡 CLB,每月750个小时 15LCU
简介: Spring Cloud Gateway 源码剖析之配置初始化

一、前言

相信大多数公司都会有自己公司的专有网关服务,虽说是自研,但很少会有从零开始开发一个网关服务,基本上是基于市面上比较流行的网关组件像 Zuul、Gateway、Soul 等进行二次封装的。那如果自己公司有相应的网关业务需求的话,这就要对网关产品的底层原理要比较熟悉了,这样做起来也比较顺手。本系列只针对 Gateway 组件进行源码剖析,我在想第一篇如何说会比较好,本来想直接说核心流程的,想了想还是先从配置初始化说起。话不多说,接下来我们就开始 Spring Cloud Gateway 源码剖析之旅吧。

二、揭秘配置初始化

那我们就从项目中 maven 依赖的 jar 包开始吧。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

直接跟进去发现有三个依赖,凭借我们的开发经验,盲猜一下 spring-cloud-gateway-core 就是 gateway 的核心依赖。

直接找到对应的 maven 依赖包:

不知道大家有没有什么疑问,找了这个包,然后 gateway 是怎么与 Spring Boot 项目相关联的呢?

相信有一定经验的朋友知道 Spring Boot 启动的时候有个 @SpringBootApplication 注解,而这个注解包含了一个非常重要的子注解 @EnableAutoConfiguration,该注解表示开启自动配置功能,是 Spring Boot 框架最重要的注解,也是实现自动化配置的注解。

Spring Cloud Gateway 也是同样的套路,那我们直接找到 /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.GatewayLoadBalancerClientAutoConfiguration,

// 度量相关依赖配置信息

org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,

// 流控的依赖配置信息

org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,

// 注册中心相关的依赖配置

org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration

分析上面的自动配置之前,我们先来了解下 SpringBoot 常用注解的含义。

// 执行顺序

@AutoConfigureBefore:在指定的配置类初始化前加载

@AutoConfigureAfter:在指定的配置类初始化后再加载

@AutoConfigureOrder:数越小越先初始化

// 条件配置

@ConditionalOnClass :classpath中存在该类时起效

@ConditionalOnMissingClass :classpath中不存在该类时起效

@ConditionalOnBean :DI容器中存在该类型Bean时起效

@ConditionalOnMissingBean :DI容器中不存在该类型Bean时起效

@ConditionalOnSingleCandidate :DI容器中该类型Bean只有一个或@Primary的只有一个时起效

@ConditionalOnExpression :SpEL表达式结果为true时

@ConditionalOnProperty :参数设置或者值一致时起效

@ConditionalOnResource :指定的文件存在时起效

@ConditionalOnJndi :指定的JNDI存在时起效

@ConditionalOnJava :指定的Java版本存在时起效

@ConditionalOnWebApplication :Web应用环境下起效

@ConditionalOnNotWebApplication :非Web应用环境下起效

1、GatewayClassPathWarningAutoConfiguration

GatewayClassPathWarningAutoConfiguration 用于检查项目是否正确导入 spring-boot-starter-webflux 依赖,而不是错误导入 spring-boot-starter-web 依赖,同时 GatewayClassPathWarningAutoConfiguration 在 EnableAutoConfiguration 配置加载前加载。

@Configuration
// 执行顺序注解
// 当前注解标识需要在GatewayAutoConfiguration前加载此配置
@AutoConfigureBefore({GatewayAutoConfiguration.class})
public class GatewayClassPathWarningAutoConfiguration {
    private static final Log log = LogFactory.getLog(GatewayClassPathWarningAutoConfiguration.class);
    private static final String BORDER = "\n\n**********************************************************\n\n";
    public GatewayClassPathWarningAutoConfiguration() {
    }
    @Configuration
    // 条件判断注解
    // classpath中不存在org.springframework.web.reactive.DispatcherHandler时起效,标识项目未导入了spring-boot-starter-webflux包
    @ConditionalOnMissingClass({"org.springframework.web.reactive.DispatcherHandler"})
    protected static class WebfluxMissingFromClasspathConfiguration {
        public WebfluxMissingFromClasspathConfiguration() {
            // 当前项目未导入了spring-boot-starter-webflux依赖时,打印警告日志
            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");
        }
    }
    @Configuration
    // 条件判断注解
    // classpath中存在org.springframework.web.servlet.DispatcherServlet时起效,标识项目导入了spring-boot-starter-web包
    @ConditionalOnClass(
        name = {"org.springframework.web.servlet.DispatcherServlet"}
    )
    protected static class SpringMvcFoundOnClasspathConfiguration {
        public SpringMvcFoundOnClasspathConfiguration() {
            // 当前项目导入了spring-boot-starter-web依赖时,打印警告日志
            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");
        }
    }
}


2、GatewayAutoConfiguration

GatewayAutoConfiguration 是 Spring Cloud Gateway 核心配置类,这里只列几个核心的,初始化如下 :

  • RoutePredicateHandlerMapping:查找匹配到 Route 并进行处理
  • GatewayProperties:加载网关配置
  • RouteDefinitionRouteLocator:创建一个根据 RouteDefinition 转换的路由定位器
  • GatewayWebfluxEndpoint:管理网关的 HTTP API


@Configuration
// 条件注解
// 通过 spring.cloud.gateway.enabled 配置网关的开启与关闭
// matchIfMissing = true => 网关默认开启。
@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 {
    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 RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> GatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, @Qualifier("webFluxConversionService") ConversionService conversionService) {
        return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties, conversionService);
    }
    @Bean
    @Primary
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
        return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }
    @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();
    }
    ...
}


3、GatewayLoadBalancerClientAutoConfiguration

GatewayLoadBalancerClientAutoConfiguration 作用是初始化 LoadBalancerClientFilter 路由的负载均衡拦截器

@Configuration
// 条件判断注解
// classpath中存在LoadBalancerClient和RibbonAutoConfiguration和DispatcherHandler时此配置起效
@ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
// 执行顺序注解
@AutoConfigureAfter({RibbonAutoConfiguration.class})
@EnableConfigurationProperties({LoadBalancerProperties.class})
public class GatewayLoadBalancerClientAutoConfiguration {
    public GatewayLoadBalancerClientAutoConfiguration() {
    }
    @Bean
    // 条件判断注解
    // DI容器中存在LoadBalancerClient类型Bean时起效
    @ConditionalOnBean({LoadBalancerClient.class})
    @ConditionalOnMissingBean({LoadBalancerClientFilter.class})
    public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client, LoadBalancerProperties properties) {
        return new LoadBalancerClientFilter(client, properties);
    }
}

4、GatewayMetricsAutoConfiguration

GatewayMetricsAutoConfiguration 作用是初始化 GatewayMetricsFilter 路由的度量拦截器

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

5、GatewayRedisAutoConfiguration

GatewayRedisAutoConfiguration 配置作用是初始化初始化 RedisRateLimiter 限流功能的,RequestRateLimiterGatewayFilterFactory 基于 RedisRateLimiter 实现网关的限流功能。

@Configuration
@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
    public ReactiveRedisTemplate<String, String> stringReactiveRedisTemplate(ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
        RedisSerializer<String> serializer = new StringRedisSerializer();
        RedisSerializationContext<String, String> serializationContext = RedisSerializationContext.newSerializationContext().key(serializer).value(serializer).hashKey(serializer).hashValue(serializer).build();
        return new ReactiveRedisTemplate(reactiveRedisConnectionFactory, serializationContext);
    }
    @Bean
    @ConditionalOnMissingBean
    public RedisRateLimiter redisRateLimiter(ReactiveRedisTemplate<String, String> redisTemplate, @Qualifier("redisRequestRateLimiterScript") RedisScript<List<Long>> redisScript, Validator validator) {
        return new RedisRateLimiter(redisTemplate, redisScript, validator);
    }
}

6、GatewayDiscoveryClientAutoConfiguration

GatewayDiscoveryClientAutoConfiguration 的作用是初始化配置路由中的注册发现服务信息

@Configuration
// 同2
@ConditionalOnProperty(
    name = {"spring.cloud.gateway.enabled"},
    matchIfMissing = true
)
@AutoConfigureBefore({GatewayAutoConfiguration.class})
@AutoConfigureAfter({CompositeDiscoveryClientAutoConfiguration.class})
@ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
    public GatewayDiscoveryClientAutoConfiguration() {
    }
    @Bean
    // 当classpath中存在DiscoveryClient起效
    @ConditionalOnBean({DiscoveryClient.class})
    // 通过spring.cloud.gateway.discovery.locator.enabled配置注册中心查找的开启与关闭
    @ConditionalOnProperty(
        name = {"spring.cloud.gateway.discovery.locator.enabled"}
    )
    public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }
    @Bean
    public DiscoveryLocatorProperties discoveryLocatorProperties() {
        DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
        properties.setPredicates(initPredicates());
        properties.setFilters(initFilters());
        return properties;
    }
    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;
    }
}

三、总结

通过自动加载初始化上述六个配置实例,Spring Cloud Gateway 就完成自身的加载和初始化工作。跟着老周下来应该还算清晰吧,下一篇我们来说一下 Route 数据模型,敬请期待~



欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。


喜欢的话,点赞、再看、分享三连。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1天前
|
负载均衡 Java API
使用Spring Cloud构建Java微服务架构
使用Spring Cloud构建Java微服务架构
|
1天前
|
负载均衡 算法 Java
Spring Cloud Netflix 之 Ribbon
Spring Cloud Netflix Ribbon是客户端负载均衡器,用于在微服务架构中分发请求。它与RestTemplate结合,自动在服务发现(如Eureka)注册的服务之间进行调用。配置包括在pom.xml中添加依赖,设置application.yml以连接Eureka服务器,并在配置类中创建@LoadBalanced的RestTemplate。通过这种方式,当调用如`/user/userInfoList`的接口时,Ribbon会自动处理到多个可用服务实例的负载均衡。
|
1天前
|
Java API 开发者
Spring Cloud Gateway中的GlobalFilter:构建强大的API网关过滤器
Spring Cloud Gateway中的GlobalFilter:构建强大的API网关过滤器
6 0
|
1天前
|
Java Maven 微服务
Spring Cloud Netflix 之 Eureka
Spring Cloud Netflix Eureka是服务发现组件,由Netflix开发,Spring Cloud集成为微服务治理工具。Eureka采用客户端/服务器架构,包含Eureka Server(服务注册中心)和Eureka Client(服务提供者和服务消费者)。服务提供者注册到Eureka Server,服务消费者通过它查找并调用服务。
|
1天前
|
负载均衡 前端开发 Java
Spring Cloud 之 OpenFeign
Spring Cloud OpenFeign是Spring官方的声明式服务调用组件,简化了远程服务调用,使其如同调用本地方法。核心注解包括`@FeignClient`、`@EnableFeignClients`、`@GetMapping`和`@PostMapping`。实践中,通过在`pom.xml`添加依赖,创建Feign接口,配置`@FeignClient`,在启动类启用Feign,以及自定义超时设置来实现远程调用和负载均衡。
|
1天前
|
监控 Java 微服务
Spring Cloud 之 Hystrix
Spring Cloud Hystrix 是一个用于处理分布式系统延迟和容错的库,防止雪崩效应。它作为断路器,当服务故障时通过监控短路,返回备用响应,保持系统弹性。主要功能包括服务降级和熔断:
|
1天前
|
监控 Java API
Spring Cloud 之 GateWay
Spring Cloud Gateway 作为API网关,处理客户端与微服务间的非业务逻辑,如权限验证、监控、路由转发。它通过Route(含ID、目标URI、Predicate和Filter)、Predicate(匹配请求条件)和Filter(请求前/后处理)实现动态路由。工作流程包括客户端请求-&gt;Gateway Handler Mapping-&gt;过滤器链-&gt;服务转发-&gt;响应过滤-&gt;回客户端。过滤器用于请求拦截、响应处理,如参数校验、权限检查。动态路由允许以服务名创建路由,实现服务发现。预设和全局过滤器用于特定或所有路由的定制逻辑,例如登录验证和请求头管理。
|
2天前
|
负载均衡 Java Spring
深入理解SpringCloud之Gateway
深入理解SpringCloud之Gateway
|
2天前
|
存储 NoSQL Java
Spring Cloud OAuth2 实现用户认证及单点登录(2)
Spring Cloud OAuth2 实现用户认证及单点登录
|
2天前
|
存储 Java 数据安全/隐私保护
Spring Cloud OAuth2 实现用户认证及单点登录(1)
Spring Cloud OAuth2 实现用户认证及单点登录