Spring Cloud Gateway 扩展动态路由

人走茶凉 提交于 2020-03-06 02:13:04

Spring Cloud Gateway 扩展动态路由

路由配置

配置文件

spring:
  application:
    name: sc-gw
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yml
        shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:                     # Route Predicate Factories
      - id: nacos-getway-provider #自定义的路由ID,保持唯一
        uri: lb://nacos-provider  #目标服务地址,以lib://开头(lb代表从注册中心获取服务)
        predicates:               #路由条件,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。
 #        - Path=/demo/service    #路由规则,为每一个服务定义一个唯一的路由前缀,所有以路由前缀开头的请求都路由到对应的服务
        - Path=/service-02/**     #Path Route Predicate Factory
        filters:                  # GatewayFilter Factories-路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器的作用域是特定的路由。
        - StripPrefix=1
      - id: nacos-getway-consumer
        uri: lb://nacos-comsumer
        predicates:
 #        - Path=/demo/serviceFeign
        - Path=/service-01/**
        filters:
        - StripPrefix=1
      - id: sc-auth
        uri: lb://sc-auth
        predicates:
        - Path=/sc-auth/**
        filters:
        - StripPrefix=1

硬编码配置

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("nacos-getway-provider",r -> r.path("/service-02/**")
               .filters(f -> f.stripPrefix(2))
               .uri("lb://nacos-provider")).build();
}
Spring Cloud Gateway 原生配置路由的方式有配置文件、硬编码。但是这两种方式存在明显的缺陷:修改路由之后必须重新启动服务路由才能生效,非常不灵活。

路由初始化过程

  1. 不管是哪种方式配置路由,每一条路由信息最终都被封装为 RouteDefination。
  2. RouteDefinationLocator 是路由信息的装载器它只有一个方法 getRouteDefinitions()。
  3. RouteDefinationLocator 有多个实现类分别对应不同的路由加载方式。
  • CachingRouteDefinitionLocator 是 RouteDefinationLocator 的一个包装类,它负责将读到的路由信息缓存到 Map。
  • CompositeRouteDefinitionLocator 是 RouteDefinationLocator 的一个包装类,它负责组合RouteDefinationLocator 的各个实现类。
  • PropertiesRouteDefinitionLocator 从配置文件中加载路由信息。
  • DiscoveryClientRouteDefinitionLocator 从注册中心加载路由信息。
  • RouteDefinitionRepository 从存储器中加载路由信息。这里的存储器包括内存、数据库
  1. RouteDefinitionRepository 有一个实现类 InMemoryRouteDefinitionRepository 。
    • InMemoryRouteDefinitionRepository 从内存中加载路由信息。
    • 没有 RouteDefinitionRepository 实例的情况下默认加载 InMemoryRouteDefinitionRepository 。
    • 通过实现 RouteDefinitionRepository 来实现动态路由。
  2. 路由加载
    • PropertiesRouteDefinitionLocator --> CompositeRouteDefinitionLocator
    • RouteDefinitionRepository --> CompositeRouteDefinitionLocator
    • DiscoveryClientRouteDefinitionLocator
    • CompositeRouteDefinitionLocator

扩展思路

  • 通过实现 RouteDefinitionRepository 接口扩展 Spring Cloud Gateway 支持从 Redis 中读取路由信息。

  • 加入二级缓存(Map)。在实现 RouteDefinitionRepository 接口的getRouteDefinations() 方法时首先从二级缓存中读取路由信息,二级缓存为空时从 Redis 中 读取路由信息,再将路由信息写入到二级缓存中。

  • 在在实现 RouteDefinitionRepository 接口的 save() / delete() 方法时通过 Redis 的发布订阅功能清空二级缓存

  • 服务启动时通过监听WebServerIntialedEvent事件进行路由初始化。初始化过程中将 Mysql 中存储的路由信息读取出来存储到 Redis 中。

  • 路由修改时首先更新 Redis ,再将路由信息持久化到 Mysql 中。通过发布 RefreshRoutesEvent 事件通过 Spring Cloud Gateway 更新路由。通过 Redis 的发布订阅功能清空二级缓存。持久化失败时回滚路由,通过发布事件重新进行路由初始化操作。

具体实现

  1. 前端页面。
  2. Controller 提供路由查询、更新接口。
  3. Service 提供路由查询、更新具体实现。
  4. 通过继承 RouteDefination 类支持序列化。创建 RouteDefinationVo 类封装数据库中存储的路由信息。
  5. 实现 RouteDefinationsRepository 接口重写 save() / delete() / getDefinations() 方法。
  6. 通过继承 ApplicationEvent 实现一个 DynamicRouteInitEvent 事件类 ,通过@EventListener 注解监听 WebServerIntialedEvent 、DynamicRouteInitEvent 事件对路由进行初始化。
  7. 创建 Redis 监听器,监听 topic 在Redis缓存更新时向指定的 topic 发布消息清空二级缓存或者重新初始化路由。
  8. 扩展 Redis 支持存储 Hash 形式的 value。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!