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 原生配置路由的方式有配置文件、硬编码。但是这两种方式存在明显的缺陷:修改路由之后必须重新启动服务路由才能生效,非常不灵活。
路由初始化过程
- 不管是哪种方式配置路由,每一条路由信息最终都被封装为 RouteDefination。
- RouteDefinationLocator 是路由信息的装载器它只有一个方法 getRouteDefinitions()。
- RouteDefinationLocator 有多个实现类分别对应不同的路由加载方式。
- CachingRouteDefinitionLocator 是 RouteDefinationLocator 的一个包装类,它负责将读到的路由信息缓存到 Map。
- CompositeRouteDefinitionLocator 是 RouteDefinationLocator 的一个包装类,它负责组合RouteDefinationLocator 的各个实现类。
- PropertiesRouteDefinitionLocator 从配置文件中加载路由信息。
- DiscoveryClientRouteDefinitionLocator 从注册中心加载路由信息。
- RouteDefinitionRepository 从存储器中加载路由信息。这里的存储器包括内存、数据库
- RouteDefinitionRepository 有一个实现类 InMemoryRouteDefinitionRepository 。
- InMemoryRouteDefinitionRepository 从内存中加载路由信息。
- 没有 RouteDefinitionRepository 实例的情况下默认加载 InMemoryRouteDefinitionRepository 。
- 通过实现 RouteDefinitionRepository 来实现动态路由。
- 路由加载
- 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 的发布订阅功能清空二级缓存。持久化失败时回滚路由,通过发布事件重新进行路由初始化操作。
具体实现
- 前端页面。
- Controller 提供路由查询、更新接口。
- Service 提供路由查询、更新具体实现。
- 通过继承 RouteDefination 类支持序列化。创建 RouteDefinationVo 类封装数据库中存储的路由信息。
- 实现 RouteDefinationsRepository 接口重写 save() / delete() / getDefinations() 方法。
- 通过继承 ApplicationEvent 实现一个 DynamicRouteInitEvent 事件类 ,通过@EventListener 注解监听 WebServerIntialedEvent 、DynamicRouteInitEvent 事件对路由进行初始化。
- 创建 Redis 监听器,监听 topic 在Redis缓存更新时向指定的 topic 发布消息清空二级缓存或者重新初始化路由。
- 扩展 Redis 支持存储 Hash 形式的 value。
来源:CSDN
作者:Fxouz
链接:https://blog.csdn.net/weixin_41341130/article/details/104677370