SpringCloudGateway路由定义存至Mysql数据库

SpringCloudGateway默认根据配置文件或代码在启动时路由定义存在内存中,如果要修改路由配置,需要改动配置文件或代码后重启网关,十分不灵活。

官方提供了RedisRouteDefinitionRepository可以将配置存放之Redis中,使用spring.cloud.gateway.redis-route-definition-repository.enabled开启。

可以实现RouteDefinitionRepository接口,将路由配置保存至Mysql中。

使用的SpringCloud版本为2021.0.5,文章编写于2022-12-12日。

ORM使用SpringDataR2DBC,相关教程请自行查找。

项目POM引入

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency><groupId>com.github.jasync-sql</groupId><artifactId>jasync-r2dbc-mysql</artifactId>
</dependency>

路由定义实体

@Table(name = "`gateway_route_define`")
public class GatewayRouteDefineEntity implements Serializable {private static final long serialVersionUID = 1L;@Idprivate String id;private String uri;private String predicates;private String filters;private String metadata;@Column("`is_enable`")private Boolean enable;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getUri() {return uri;}public void setUri(String uri) {this.uri = uri;}public String getPredicates() {return predicates;}public void setPredicates(String predicates) {this.predicates = predicates;}public String getFilters() {return filters;}public void setFilters(String filters) {this.filters = filters;}public String getMetadata() {return metadata;}public void setMetadata(String metadata) {this.metadata = metadata;}public Boolean isEnable() {return enable;}public void setEnable(Boolean enable) {this.enable = enable;}
}

DAO层

@Repository
public interface GatewayRouteDefineDao extends ReactiveCrudRepository<GatewayRouteDefineEntity, String> {/*** 查询所有启用的路由定义* @return 路由定义列表*/Flux<GatewayRouteDefineEntity> findAllByEnableTrue();
}

Service层

public interface GatewayRouteDefineService {/*** 查询所有实体** @return 路由实体列表*/Flux<GatewayRouteDefineEntity> findAll();/*** 保存** @param entity 路由实体* @return*/Mono<GatewayRouteDefineEntity> save(@RequestBody @Validated GatewayRouteDefineEntity entity);/*** 根据id删除实体** @param id 实体id* @return*/Mono<Void> deleteById(@PathVariable("id") String id);/*** 刷新路由定义** @return*/Mono<Void> refreshRouteDefinition();
}
@Service
public class GatewayRouteDefineServiceImpl implements GatewayRouteDefineService {private static final Logger log = LoggerFactory.getLogger(GatewayRouteDefineServiceImpl.class);private final GatewayRouteDefineDao gatewayRouteDefineDao;private final ApplicationEventPublisher publisher;public GatewayRouteDefineServiceImpl(GatewayRouteDefineDao gatewayRouteDefineDao,ApplicationEventPublisher publisher) {this.gatewayRouteDefineDao = gatewayRouteDefineDao;this.publisher = publisher;}@Overridepublic Flux<GatewayRouteDefineEntity> findAll() {return gatewayRouteDefineDao.findAllByEnableTrue();}@Overridepublic Mono<GatewayRouteDefineEntity> save(GatewayRouteDefineEntity entity) {return gatewayRouteDefineDao.save(entity);}@Overridepublic Mono<Void> deleteById(String id) {return gatewayRouteDefineDao.deleteById(id);}@Overridepublic Mono<Void> refreshRouteDefinition() {this.publisher.publishEvent(new RefreshRoutesEvent(this));return Mono.empty();}
}

实现RouteDefinitionRepository

@Configuration
public class RouteDefinitionConfiguration {@Beanpublic DbRouteDefinitionRepository dbRouteDefinitionRepository(GatewayRouteDefineService gatewayRouteDefineService) {return new DbRouteDefinitionRepository(gatewayRouteDefineService);}public static class DbRouteDefinitionRepository implements RouteDefinitionRepository {private final GatewayRouteDefineService gatewayRouteDefineService;public DbRouteDefinitionRepository(GatewayRouteDefineService gatewayRouteDefineService) {this.gatewayRouteDefineService = gatewayRouteDefineService;}@Overridepublic Flux<RouteDefinition> getRouteDefinitions() {return gatewayRouteDefineService.findAll().map(entity -> {try {return GatewayRouteDefineUtils.convert(entity);} catch (URISyntaxException | JsonProcessingException e) {throw new RuntimeException(e);}});}@Overridepublic Mono<Void> save(Mono<RouteDefinition> route) {return route.flatMap(r -> {try {GatewayRouteDefineEntity entity = GatewayRouteDefineUtils.convert(r);return gatewayRouteDefineService.save(entity).then();} catch (JsonProcessingException e) {return Mono.error(new RuntimeException(e));}});}@Overridepublic Mono<Void> delete(Mono<String> routeId) {return routeId.flatMap(gatewayRouteDefineService::deleteById);}}
}

工具类

public class GatewayRouteDefineUtils {private static final ObjectMapper OBJECT_MAPPER;static {OBJECT_MAPPER = new ObjectMapper();OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);}public static RouteDefinition convert(GatewayRouteDefineEntity entity) throws URISyntaxException, JsonProcessingException {RouteDefinition definition = new RouteDefinition();definition.setId(entity.getId());definition.setUri(new URI(entity.getUri()));if (entity.getPredicates() != null) {List<PredicateDefinition> predicateDefinitions = OBJECT_MAPPER.readValue(entity.getPredicates(),new TypeReference<List<PredicateDefinition>>() { });definition.setPredicates(predicateDefinitions);}if (entity.getFilters() != null) {List<FilterDefinition> filterDefinitions = OBJECT_MAPPER.readValue(entity.getFilters(),new TypeReference<List<FilterDefinition>>() { });definition.setFilters(filterDefinitions);}return definition;}public static GatewayRouteDefineEntity convert(RouteDefinition definition) throws JsonProcessingException {GatewayRouteDefineEntity entity = new GatewayRouteDefineEntity();entity.setId(definition.getId());entity.setUri(definition.getUri().toString());entity.setPredicates(OBJECT_MAPPER.writeValueAsString(definition.getPredicates()));entity.setFilters(OBJECT_MAPPER.writeValueAsString(definition.getFilters()));return entity;}
}

测试Controller

@RestController
public class TestController {private static final Logger log = LoggerFactory.getLogger(TestController.class);private final GatewayRouteDefineService gatewayRouteDefineService;public TestController(GatewayRouteDefineService gatewayRouteDefineService) {this.gatewayRouteDefineService = gatewayRouteDefineService;}@RequestMapping("/refresh_route")public Mono<String> refreshRoute() {return gatewayRouteDefineService.refreshRouteDefinition().thenReturn("refresh success");}
}

数据库表

CREATE TABLE `gateway_route_define`  (`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',`uri` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '目的地址',`predicates` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '断言定义',`filters` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '过滤器定义',`metadata` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '扩展数据',`is_enable` tinyint(4) NULL DEFAULT NULL COMMENT '是否启用  0:否  1:是',`create_time` datetime(3) NULL DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '网关路由定义表' ROW_FORMAT = Dynamic;

插入一条测试数据

INSERT INTO `gateway_route_define` VALUES ('c707a482-77a3-11ed-a1eb-0242ac120002', 'https://www.baidu.com', '[{\"name\":\"Path\",\"args\":{\"pattern\":\"/baidu\"}}]', '[{\"name\":\"RewritePath\",\"args\":{\"regexp\":\"/baidu/?(?<segment>.*)\",\"replacement\":\"/$\\\\{segment}\"}},{\"name\":\"GuavaRateLimiter\",\"args\":{\"limit\":\"5\"}}]', '{}', 1, '2022-12-12 11:46:55.000');

其实数据库保存的字段就是RouteDefinition类中的字段,其中predicates、filters、metadata字段为JSON格式的数据。

路由定义序列化

Predicate序列化

其实就是对PredicateDefinition类进行序列化,包含name和args两个字段,其中args需要去org.springframework.cloud.gateway.handler.predicate路径下找具体的工厂类,里面有各参数的名称
例如

spring:cloud:gateway:routes:- id: path_routeuri: https://example.orgpredicates:- Path=/red/{segment},/blue/{segment}

这条路由规则中的

Path=/red/{segment},/blue/{segment}

其实现类是PathRoutePredicateFactory,那么args参数就是由PathRoutePredicateFactory.Config序列化而来。其余predicate和filter都是按此规则,这样应该就能理解插入的测试数据中predicates和filters字段的含义了。

测试

启动网关,会自动去数据库加载路由定义,当数据库路由修改后,可以调用GatewayRouteDefineService#refreshRouteDefinition来刷新路由,其实原理就是触发一个RefreshRoutesEvent事件,SpringCloudGateway会重新加载路由。

SpringCloudGateway路由定义存至Mysql数据库相关推荐

  1. mysql 数据路由_node-路由操作mysql数据库

    node大部分方法都是异步的,在操作数据库方法后面紧接着输出结果,输出的结果只会为空值,使用promise及其方便的解决这个问题,接下来看看node如何使用路由来处理不同请求,进而操作mysql数据库 ...

  2. Python入门系列(十一)一篇搞定python操作MySQL数据库

    开始 安装MySQL驱动 $ python -m pip install mysql-connector-python 测试MySQL连接器 import mysql.connector 测试MySQ ...

  3. iis配置mysql数据库连接_iis配置mysql数据库

    [php] 实战配置 IIS PHP MYSQL 前言:网上很多 IIS PHP MYSQL 教程安装完都会出现不支持 MYSQL 的问题,因为 那些教程都不是实际操作,而这里本教程经过实际操作,.. ...

  4. mfc远程连接mysql数据库连接_MFC连接mysql数据库(十分钟搞定)

    最近要做一个大作业,需要用到数据库,sql server装了两次都失败,遂弃暗投明,用mysql,虽然我从来没有接触过,数据库么,一通百通的,5分钟就熟悉了.问题的关键是要用MFC连接mysql数据库 ...

  5. 轻松八句话 教会你完全搞定MySQL数据库(基础)

    2019独角兽企业重金招聘Python工程师标准>>> 本文让你用轻松八句话就可教会你完全搞定MySQL数据库. 一.连接MYSQL 格式: mysql -h主机地址-u用户名-p用 ...

  6. 使用开源实时监控系统 HertzBeat 5分钟搞定 Mysql 数据库监控告警

    使用开源实时监控系统 HertzBeat 对 Mysql 数据库监控告警实践,5分钟搞定! Mysql 数据库介绍 MySQL是一个开源关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 O ...

  7. MySQL数据库导入BIN格式定长文件

    环境: MySQL5.7 widows10 jdk1.8 工具:Navicat Premium 11.1.14.0  eclipse mar2 实现思路: 因为没有分隔符对数据进行分割,所以不能使用 ...

  8. mysql数据库根据经纬度计算距离,获取离我最近的地点列表,并排序。附近的人,附近商店等功能,一个sql就搞定

    mysql数据库根据经纬度计算距离,获取离我最近的地点列表,并排序 附近的人,附近商家等功能,顺序显示顺序是由近到远的,便利用户查看和判断,sql实现如下. StringBuilder sb=new ...

  9. 超简单的Jmeter连接mysql数据库,3分钟搞定!

    目录:导读 一.确保mysql数据库能够通过Navicat等远程连接工具连接. 二.下载驱动并加入jmeter 三.配置jmeter连接mysql数据库 四.总结 一.确保mysql数据库能够通过Na ...

最新文章

  1. 面对众多的前端框架,你该如何学习?
  2. 【Python文件处理】递归批处理文件夹子目录内所有txt数据
  3. c++ 一个函数包括多个返回值判断_Python函数的概念和使用
  4. LeetCode 编辑距离 II(DP)
  5. intel编译器_Intel编译器编译并行版lammps
  6. LOJ 2085: 洛谷 P1587: bzoj 4652: 「NOI2016」循环之美
  7. 下面两种送礼模式会让你的生意兴隆
  8. 思科接入层交换机故障
  9. 电子邮件服务器-PostFix
  10. 东力减速机电机型号_东力齿轮减速电机的选型
  11. 泛函分析 06.02 线性算子的谱理论 - 有界线性算子的谱集
  12. 微信登录提示逻辑不正确_微信逻辑错误无法登录
  13. scrapy框架之spider
  14. 怎么看rx580是不是470刷的_rx580显卡怎么看是不是矿卡 rx580显卡怎么看是不是刷的...
  15. 三层锁机病毒的层层逆向剖析
  16. Transformer靠什么基因,得以闯入CV界秒杀CNN?
  17. 安装Ubuntu系统卡在载入界面,显示正在安装open vm tools
  18. Python处理txt文件:多句分行+行首尾添加字符+for循环--Python新手自练系列
  19. 带你玩转序列模型之循环神经网络(一)
  20. Go Web 编程 PDF

热门文章

  1. 【RL系列】Multi-Armed Bandit问题笔记
  2. 单边指数信号的特点_单边带通信的特点
  3. Altium Designer 18安装教程(内含crack和package)
  4. 敏捷测试 之 借力DSL
  5. 空间日志html,30条空间日志个性签名
  6. An End-to-End Steel Surface Defect Detection Approach via Fusing Multiple Hierarchical Features
  7. apache带宽配置
  8. XSS Cheat Sheet
  9. 浙大计算机跨专业考研心路历程记录
  10. 猜数游戏(GAMBLER)