基于RouteDefinitionRepository实现基于mysql的路由声明加载

1.背景

RouteDefinition和Route这两个是springcloud gateway中的路由关键实体,RouteDefinition是给外部使用的,我们可以通过实现RouteDefinitionLocator 接口,来实现对路由声明获取方式的自定义。

RouteDefinitionLocator 是从外部,比如从属性文件,jvm内存,redis,discovery client加载路由声明到springcloud gateway中。

RouteLocator 是从RouteDefinitionLocator中获取路由声明,然后转化为springcloud gateway可以使用的路由Route

RouteDefinitionRoute其实主要是断言匹配器的映射和过滤器的映射:

将RouteDefinition中PredicateDefinition中的name通过RoutePredicateFactory 生成对应的GatewayPredicate 路由匹配断言对象。

将RouteDefinition中FilterDefinition中的name通过GatewayFilterFactory 生成对应的GatewayFilter 网关过滤器对象。


2. RouteDefinitionLocator的子类介绍

基于RouteDefinitionRepository实现基于mysql的路由声明加载_第1张图片

CachingRouteDefinitionLocator:路由声明缓存器

CompositeRouteDefinitionLocator: 基于组合模式的管理其他的RouteDefinitionLocator实现类

PropertiesRouteDefinitionLocator: 基于配置的路由声明加载器

InMemoryRouteDefinitionRepository: 基于jvm内存的路由声明加载器,可以通过接口对缓存在内存中的路由声明进行新增和删除。

RedisRouteDefinitionLocatorRepository: 基于redis的路由声明加载器,可以通过接口对缓存在redis中的路由声明进行增删。

DiscoveryClientRouteDefinitionRepository: 基于服务发现的路由声明加载器,默认是以spring.application.name作为Path断言的前缀来实现路由的。

默认情况下:

CachingRouteDefinitionLocator 通过CompositeRouteDefinitionLocator 进行路由声明加载,然后缓存在自己的容器中。

CompositeRouteDefinitionLocator 里面管理着PropertiesRouteDefinitionLocator


3.自定义mysql路由声明加载器MySqlRouteDefinitionLocatorRepository

通过实现RouteDefinitionRepository 接口,来实现基于mysql路由声明加载器。

/**
* RouteDefinitionLocator 提供了获取路由声明的接口
* RouteDefinitionWriter 提供了路由删除与新增接口
*/
public interface RouteDefinitionRepository extends RouteDefinitionLocator, RouteDefinitionWriter {
}

3.1 自定义实现

package com.gu.gateway.frame.route;

import com.gu.gateway.service.IServiceRouteDefinitionLocator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 从数据库中加载路由声明
 */
@Component
public class MySqlRouteDefinitionLocatorRepository implements RouteDefinitionRepository {

    @Autowired
    IServiceRouteDefinitionLocator serviceRouteDefinitionLocator;
    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        // 拉取数据库配置进行路由读取
        List<RouteDefinition> routeDefinitionList = serviceRouteDefinitionLocator.getRouteDefinitionList();
        // 将List的RouteDefinition转化为Flux的异步序列
        return Flux.fromIterable(routeDefinitionList);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        // todo 进行路由写入到mysql数据库
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        // todo 从mysql中删除路由
        return null;
    }
}

IServiceRouteDefinitionLocator主要功能将数据库中的路由声明信息转为List

其中主要代码为:

ServiceRouteDefinition 转为RouteDefinition

ServiceRoutePredicate 转为 PredicateDefinition

ServiceRouteFilter 转为 FilterDefinition

ServiceRouteMetadata 转为 RouteDefinition 的metadata

代码太多,就不贴了,稍后贴出gitee仓库地址。


4. mysql的路由声明表结构

CREATE TABLE `service_route_predicate` (
  `id` int NOT NULL AUTO_INCREMENT,
  `route_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `predicate_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `predicate_arg_name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `predicate_arg_value` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `in_use` int NOT NULL DEFAULT '0',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `edit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `service_route_metadata` (
  `id` int NOT NULL AUTO_INCREMENT,
  `route_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `meta_key` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `meta_value` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `in_use` int NOT NULL DEFAULT '0',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `edit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `service_route_filter` (
  `id` int NOT NULL AUTO_INCREMENT,
  `route_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `filter_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `filter_arg_name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `filter_arg_value` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `in_use` int NOT NULL DEFAULT '0',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `edit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `service_route_definition` (
  `id` int NOT NULL AUTO_INCREMENT,
  `route_id` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `route_uri` varchar(64) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `route_order` int NOT NULL DEFAULT '0',
  `in_use` int NOT NULL DEFAULT '0',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `edit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
sql:
INSERT INTO `service_route_definition` (`id`, `route_id`, `route_uri`, `route_order`, `in_use`, `create_time`, `edit_time`) 
VALUES (1, 'sop-boot-provider', 'lb://sop-boot-provider', 1, 1, '2023-03-13 11:40:54', '2023-03-14 05:18:08');
INSERT INTO `service_route_filter` (`id`, `route_id`, `filter_name`, `filter_arg_name`, `filter_arg_value`, `in_use`, `create_time`, `edit_time`) 
VALUES (1, 'sop-boot-provider', 'StripPrefix', '_genkey_0', '1', 1, '2023-03-13 11:49:26', '2023-03-14 05:15:08');
INSERT INTO `service_route_predicate` (`id`, `route_id`, `predicate_name`, `predicate_arg_name`, `predicate_arg_value`, `in_use`, `create_time`, `edit_time`) 
VALUES (1, 'sop-boot-provider', 'Path', '_genkey_0', '/provider/**', 1, '2023-03-13 11:45:57', '2023-03-14 05:14:59');

5. 结果

在这里插入图片描述

基于RouteDefinitionRepository实现基于mysql的路由声明加载_第2张图片

从这里可以看到,sop-boot-consumer是通过配置文件声明的,而sop-boot-provider是通过数据库进行加载的。

这样就实现了基于mysql的自定义路由声明加载器功能了。


6.存在问题

路由生效具备时间差

当前路由刷新的功能是通过NacosWatch的定时任务发布HeartBeatEvent事件

RouteRefreshListener 监听到HeartBeatEvent,就发布RefreshRoutesEvent 事件

这个时候,RefreshRoutesEvent就会被CachingRouteLocator 监听到从而实现路由的重新加载功能。

预备解决方案:

基于服务发现的方式去加载路由和删除路由。就是修改service_route_definition表中的in_use字段。

你可能感兴趣的:(springcloud,gateway,java,gateway,路由)