首页 > 编程语言 > SpringCloud Gateway 利用 Mysql 实现动态路由的方法
2021
02-21

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

需求描述

标准网关动态路由功能是重要的一环,将路由、断言以及过滤器信息,持久化到 Mysql 中,通过配置后台页面实现路由、断言、以及过滤器等配置的增删改查。

Spring Cloud Gateway 路由及黑白名单实现背景 Spring Cloud 路由API

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 配置文件路由加载方式

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 类图

WhitelistGatewayFilterFactory 类图

动态路由设计 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

接口类图 路由及黑白名单类图

断言及过滤器封装类图

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

路由初始化设计 重载 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 实现动态路由内容请搜索自学编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持自学编程网!

编程技巧