评论

收藏

[Java] SpringCloud Gateway 利用 Mysql 实现动态路由的方法

编程语言 编程语言 发布于:2021-09-11 23:31 | 阅读数:503 | 评论:0

这篇文章主要介绍了SpringCloud Gateway 利用 Mysql 实现动态路由的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
需求描述
标准网关动态路由功能是重要的一环,将路由、断言以及过滤器信息,持久化到 Mysql 中,通过配置后台页面实现路由、断言、以及过滤器等配置的增删改查。
Spring Cloud Gateway 路由及黑白名单实现背景 Spring Cloud 路由API
DSC0000.png

Spring Cloud Gateway 通过定义 RouteDefinitionRepository 来实现动态路由.
//保存路由缓存
public interface RouteDefinitionWriter {
  Mono<Void> save(Mono<RouteDefinition> route);
  Mono<Void> delete(Mono<String> routeId);
}
//获取路由缓存
public interface RouteDefinitionLocator {
  Flux<RouteDefinition> getRouteDefinitions();
}
Spring Cloud 配置文件路由加载方式
DSC0001.png
public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
  private final GatewayProperties properties;
  public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
   this.properties = properties;
  }
  @Override
  public Flux<RouteDefinition> getRouteDefinitions() {
   return Flux.fromIterable(this.properties.getRoutes());
  }
}
Spring Cloud 黑白名 FilterFactory
利用 Spring Cloud Gateway 声明的一个工厂接口 GatewayFilterFactory, 定义 黑白名单过滤器
BlacklistGatewayFilterFactory 类图
DSC0002.png

WhitelistGatewayFilterFactory 类图
DSC0003.png

动态路由设计 Spring Cloud Gateway 路由实体类
Spring Cloud Gateway 通过定义 RouteDefinition 类装载路由信息。
package org.springframework.cloud.gateway.route;
public class RouteDefinition {
  //路由 ID
  @NotEmpty
  private String id = UUID.randomUUID().toString();
  //断言数组
  @NotEmpty
  @Valid
  private List<PredicateDefinition> predicates = new ArrayList<>();
  //过滤器数组
  @Valid
  private List<FilterDefinition> filters = new ArrayList<>();
  // 路由地址
  @NotNull
  private URI uri;
  // 路由顺序
  private int order = 0;
}
数据库设计
路由表
drop table if exists gateway_route_t;
create table if not exists gateway_route_t
(
  ID   int auto_increment primary key,
  ROUTE_ID  varchar(255) not null comment "路由ID",
  ROUTE_ORDER int default 0 null comment "路由顺序",
  URI   varchar(255) not null comment "路由路径",
  VALID  int default 1 not null comment "是否有效:0-无效,1-有效",
  CREATE_USER varchar(200) null comment "创建人",
  CREATE_TIME datetime   null comment "创建时间",
  UPDATE_USER varchar(200) null comment "修改人",
  UPDATE_TIME datetime   null comment "修改时间",
  constraint idx_ROUTE_ID_index unique (ROUTE_ID)
) comment "网关路由信息表" charset = utf8;
路由参数表
drop table if exists gateway_route_param_t;
create table if not exists gateway_route_param_t
(
  ID   int auto_increment primary key,
  ROUTE_ID  varchar(255) not null comment "路由ID",
  PARAM_NAME varchar(255) not null comment "参数name",
  PARAM_KEY  varchar(255) not null comment "参数 key",
  PARAM_VALUE varchar(255) not null comment "参数 value",
  TYPE  int    not null comment "参数类型,1为 predicate,2为过 filter",
  VALID  int default 1 not null comment "是否有效:0-无效,1-有效",
  CREATE_USER varchar(200) null comment "创建人",
  CREATE_TIME datetime   null comment "创建时间",
  UPDATE_USER varchar(200) null comment "修改人",
  UPDATE_TIME datetime   null comment "修改时间"
) comment "网关路由参数表" charset = utf8;
create index idx_route_id on gateway_route_param_t (ROUTE_ID);
接口设计 接口定义
路由表配置接口
封装 gateway_route_t dao 层接口.
/**
 * <功能描述> 路由表接口
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IRouteConfigService extends IService<RouteDomain>
路由参数表配置接口
封装 gateway_route_param_t dao 层接口.
/**
 * <功能描述> 路由参数表接口
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IRouteParamConfigService extends IService<RouteParamDomain>
数据库路由服务接口
封装 路由表配置服务接口以及路由参数表配置接口, 对外层提供对数据库路由信息的操作.
/**
 * <功能描述> 数据库路由服务
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IRoutePropertiesService
网关路由缓存接口
封装 RouteDefinitionRepository 接口,对外提供对网关路由缓存的刷新.
/**
 * <功能描述> 网关缓存路由服务
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IGatewayRouteService extends ApplicationEventPublisherAware
路由事件监听接口
配置需要监听路由变化的 service 实现
/**
 * <功能描述> 路由事件监听接口
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface RouteEventListener extends ApplicationListener<RefreshCacheEvent>
数据库黑白名单配置接口
/**
 * <功能描述> API Filter 接口定义
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IApiFilterService
网关白名单缓存接口
提供指定路由 API 白名单check 监听路由事件
/**
 * <功能描述> API 白名单缓存接口
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IApiCacheService extends RouteEventListener
路由参数执行校验接口
封装 提供路由参数的校验的接口.
/**
 * <功能描述> 路由参数校验
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
public interface IRouteValidateExecutorService
接口类图 路由及黑白名单类图
DSC0004.png

断言及过滤器封装类图
DSC0005.png

集群缓存刷新事件处理策略类图
DSC0006.png

路由初始化设计 重载 PropertiesRouteDefinitionLocator
/**
 * <功能描述> 重写 PropertiesRouteDefinitionLocator bean
 * 将配置文件中的路由信息通过 MysqlRouteConfig 载入。
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
@Configuration
@AutoConfigureBefore({MysqlRouteConfig.class})
public class PropertiesRouteConfig {
  @Bean
  public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
    GatewayProperties properties) {
  return new PropertiesRouteDefinitionLocator(new GatewayProperties());
  }
}
定义 initMysqlRouteDefinition Bean 加载数据库及配置文件的路由配置
/**
 * <功能描述> 从Mysql中初始化路由信息
 * 覆盖配置文件中的路由信息
 *
 * @author 20024322
 * @date 2020/12/24 13:20
 */
@Configuration
public class MysqlRouteConfig {
  private final IRoutePropertiesService routePropertiesService;
  private final IGatewayRouteService gatewayRouteService;
  public MysqlRouteConfig(IRoutePropertiesService routePropertiesService, IGatewayRouteService gatewayRouteService) {
  this.routePropertiesService = routePropertiesService;
  this.gatewayRouteService = gatewayRouteService;
  }
  /**
   * 初始化 gatewayProperties 中的 route
   *
   * @param gatewayProperties
   * @return
   */
  @Bean
  public List<RouteDefinition> initMysqlRouteDefinition(GatewayProperties gatewayProperties) {
  List<RouteDefinition> gatewayPropertiesRoutes = gatewayProperties.getRoutes();
  //初始化数据库路由信息
  List<RouteDefinition> routeDefinitionList = routePropertiesService.getRouteDefinitionList();
  if (CollectionUtils.isEmpty(gatewayProperties.getRoutes()) && CollectionUtils.isEmpty(routeDefinitionList)) {
    throw new BizBaseException(HprmcExceptionCode.ROUTE_NOT_FOUND);
  }
  Set<String> routeIds = routeDefinitionList.stream()
    .map(RouteDefinition::getId).collect(Collectors.toSet());
  if (gatewayPropertiesRoutes.stream().anyMatch(r -> routeIds.contains(r.getId()))) {
    throw new BizBaseException(HprmcExceptionCode.ROUTE_INIT_CONFLICT);
  }
  //将配置文件中的路由信息添加到 InMemoryRouteDefinitionRepository 成员变量中
  if (!CollectionUtils.isEmpty(gatewayPropertiesRoutes)) {
    gatewayPropertiesRoutes.forEach(gatewayRouteService::addInMemoryRouteRefresh);
  }
  //写到 InMemoryRouteDefinitionRepository 成员初始化缓存
  if (!CollectionUtils.isEmpty(routeDefinitionList)) {
    routeDefinitionList.forEach(gatewayRouteService::addInMemoryRouteRefresh);
  }
  return routeDefinitionList;
  }
}
到此这篇关于SpringCloud Gateway 利用 Mysql 实现动态路由的方法的文章就介绍到这了,更多相关SpringCloud Gateway 实现动态路由内容请搜索CodeAE代码之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持CodeAE代码之家!
原文链接:https://juejin.cn/post/6928933330029117448

关注下面的标签,发现更多相似文章