Spring-Cloud-Gateway 源码解析 —— 路由(1.4)之 DiscoveryClientRouteDefinitionLocator 注册中心

摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud-Gateway/route-definition-locator-discover-client/ 「芋道源码」欢迎转载,保留摘要,谢谢!

本文主要基于 Spring-Cloud-Gateway 2.0.X M4


1. 概述

本文主要对 DiscoveryClientRouteDefinitionLocator 的源码实现

DiscoveryClientRouteDefinitionLocator 通过调用 org.springframework.cloud.client.discovery.DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组。


推荐 Spring Cloud 书籍

推荐 Spring Cloud 视频

2. 环境搭建

在解析源码之前,我们先以 Eureka 为注册中心,讲解下如何配置 DiscoveryClientRouteDefinitionLocator 。

第一步,以 spring-cloud-gateway-sample 项目为基础,在 pom.xml 文件添加依赖库。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>2.0.0.M1</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  • 注意,需要排除 spring-boot-starter-web 的依赖,避免和 Spring Cloud Gateway 依赖的 spring-boot-starter-webflux 冲突。

第二步,在 application.yml 添加 Eureka 相关配置 。

spring:
  application:
      name: juejin-gateway

eureka:
  instance:
    leaseRenewalIntervalInSeconds: 10
    leaseExpirationDurationInSeconds: 30
  client:
    serviceUrl:
      defaultZone: http://eureka.didispace.com/eureka/  

第三步,在 org.springframework.cloud.gateway.sample.GatewaySampleApplication 里,添加 RouteDefinitionLocator Bean 配置。

@EnableDiscoveryClient // {@link DiscoveryClientRouteDefinitionLocator}
public class GatewaySampleApplication {

    // ... 省略其他代码

    @Bean
    public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
    }
}

第四步,启动一个注册在 Eureka 的应用服务。机智如你,这里我就不啰嗦落。

第五步,在 DiscoveryClientRouteDefinitionLocator 的 #getRouteDefinitions() 方法打断点,调试启动 spring-cloud-gateway-sample 。小功告成。撒花~

3. DiscoveryClientRouteDefinitionLocator

org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator ,通过调用 DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组。

代码如下 :

  1: public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
  2:
  3:    private final DiscoveryClient discoveryClient;
  4:    private final String routeIdPrefix;
  5:
  6:    public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
  7:        this.discoveryClient = discoveryClient;
  8:        this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
  9:    }
 10:
 11:    @Override
 12:    public Flux<RouteDefinition> getRouteDefinitions() {
 13:        return Flux.fromIterable(discoveryClient.getServices())
 14:                .map(serviceId -> {
 15:                    RouteDefinition routeDefinition = new RouteDefinition();
 16:                    // 设置 ID
 17:                    routeDefinition.setId(this.routeIdPrefix + serviceId);
 18:                    // 设置 URI
 19:                    routeDefinition.setUri(URI.create("lb://" + serviceId));
 20:
 21:                    // add a predicate that matches the url at /serviceId
 22:                    /*PredicateDefinition barePredicate = new PredicateDefinition();
 23:                    barePredicate.setName(normalizePredicateName(PathRoutePredicateFactory.class));
 24:                    barePredicate.addArg(PATTERN_KEY, "/" + serviceId);
 25:                    routeDefinition.getPredicates().add(barePredicate);*/
 26:
 27:                    // 添加 Path 匹配断言
 28:                    // add a predicate that matches the url at /serviceId/**
 29:                    PredicateDefinition subPredicate = new PredicateDefinition();
 30:                    subPredicate.setName(normalizePredicateName(PathRoutePredicateFactory.class));
 31:                    subPredicate.addArg(PATTERN_KEY, "/" + serviceId + "/**");
 32:                    routeDefinition.getPredicates().add(subPredicate);
 33:
 34:                    //TODO: support for other default predicates
 35:
 36:                    // 添加 Path 重写过滤器
 37:                    // add a filter that removes /serviceId by default
 38:                    FilterDefinition filter = new FilterDefinition();
 39:                    filter.setName(normalizeFilterName(RewritePathGatewayFilterFactory.class));
 40:                    String regex = "/" + serviceId + "/(?<remaining>.*)";
 41:                    String replacement = "/${remaining}";
 42:                    filter.addArg(REGEXP_KEY, regex);
 43:                    filter.addArg(REPLACEMENT_KEY, replacement);
 44:                    routeDefinition.getFilters().add(filter);
 45:
 46:                    //TODO: support for default filters
 47:
 48:                    return routeDefinition;
 49:                });
 50:    }
 51: }

4. 高能

本小节建议阅读完 《Spring-Cloud-Gateway 源码解析 —— 路由(2.1)之 RouteLocator 一览》 再理解。

RoutePredicateHandlerMapping 使用 CachingRouteLocator 来获取 Route 信息。在 Spring Cloud Gateway 启动后,如果有新加入的服务,则需要刷新 CachingRouteLocator 缓存

这里有一点需要注意下 :新加入的服务,指的是新的 serviceId ,而不是原有服务新增的实例。

个人建议,写一个定时任务,间隔调用 DiscoveryClient 获取服务列表,若发现变化,刷新 CachingRouteLocator 缓存

赞(0) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » Spring-Cloud-Gateway 源码解析 —— 路由(1.4)之 DiscoveryClientRouteDefinitionLocator 注册中心
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 技术驿站 | 致力打造 Java 精品博客

联系作者优质文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏