spring cloud gateway 实现redis动态路由及自动项目路由上报
前言
spring cloud gateway默认为内存存储策略,通过配置文件加载的方式生成路由定义信息


可以看到,RouteDefinitionRepository继承了两个父接口,分别为RouteDefinitionLocator和RouteDefinitionWriter,RouteDefinitionLocator定义了路由定义获取接口,而RouteDefinitionWriter则定义了路由定义保存更新save接口和删除接口。
可以看到RouteDefinitionRepository是核心接口,其默认的实现类有上图两个,分别是基于内存和基于redis的,如果需要redis实现动态路由则只需要实现RouteDefinitionRepository接口并注入bean即可
一、实现RouteDefinitionRepository接口
这里其实spring cloud gateway已经有默认实现了的基于redis 的路由定义相关的repository,但由于其并没有做本地缓存,是纯redis的方式读取写入,这样会导致在进行路由调用的时候频繁的调用其getRouteDefinitions方法,频繁的读取redis其实也是有一定的性能损耗,因此我们其实稍加利用,添加本地缓存即可(本示例使用咖啡因缓存),注意添加注解:@EnableCaching
/*** @classDesc:* @author: cyjer* @date: 2023/1/30 9:53*/
@Component
@Slf4j
public class RedisRouteRepository implements RouteDefinitionRepository {private static final String ROUTE_DEFINITION_REDIS_KEY_PREFIX_QUERY = "routeDefinition::";private final ReactiveRedisTemplate<String, RouteDefinition> reactiveRedisTemplate;private final ReactiveValueOperations<String, RouteDefinition> routeDefinitionReactiveValueOperations;public RedisRouteRepository(ReactiveRedisTemplate<String, RouteDefinition> reactiveRedisTemplate) {this.reactiveRedisTemplate = reactiveRedisTemplate;this.routeDefinitionReactiveValueOperations = reactiveRedisTemplate.opsForValue();}@Override@Cacheable(cacheNames = "redisRoute")public Flux<RouteDefinition> getRouteDefinitions() {log.info("<<<<<<<<<<获取路由信息>>>>>>>>>>");return this.reactiveRedisTemplate.keys(this.createKey("*")).flatMap((key) -> {return this.reactiveRedisTemplate.opsForValue().get(key);}).onErrorContinue((throwable, routeDefinition) -> {if (log.isErrorEnabled()) {log.error("get routes from redis error cause : {}", throwable.toString(), throwable);}});}@Override@CacheEvict(cacheNames = "redisRoute")public Mono<Void> save(Mono<RouteDefinition> route) {log.info("<<<<<<<<<<保存路由信息>>>>>>>>>>");return route.flatMap((routeDefinition) -> {return this.routeDefinitionReactiveValueOperations.set(this.createKey(routeDefinition.getId()), routeDefinition).flatMap((success) -> {return success ? Mono.empty() : Mono.defer(() -> {return Mono.error(new RuntimeException(String.format("Could not add route to redis repository: %s", routeDefinition)));});});});}@Override@CacheEvict(cacheNames = "redisRoute")public Mono<Void> delete(Mono<String> routeId) {log.info("<<<<<<<<<<删除路由信息>>>>>>>>>>");return routeId.flatMap((id) -> {return this.routeDefinitionReactiveValueOperations.delete(this.createKey(id)).flatMap((success) -> {return success ? Mono.empty() : Mono.defer(() -> {return Mono.error(new NotFoundException(String.format("Could not remove route from redis repository with id: %s", routeId)));});});});}private String createKey(String routeId) {return ROUTE_DEFINITION_REDIS_KEY_PREFIX_QUERY + routeId;}}
/*** @classDesc: 本地缓存* @author: cyjer* @date: 2023/1/30 9:53*/
@Configuration
public class CaffeineConfig {@Bean@Primarypublic CacheManager caffeineCacheManager() {SimpleCacheManager cacheManager = new SimpleCacheManager();List<CaffeineCache> caches = new ArrayList<>();Map<String, Object> map = getCacheType();for (String name : map.keySet()) {caches.add(new CaffeineCache(name, (Cache<Object, Object>) map.get(name)));}cacheManager.setCaches(caches);return cacheManager;}/*** 初始化自定义缓存策略** @return*/private static Map<String, Object> getCacheType() {Map<String, Object> map = new ConcurrentHashMap<>();map.put("redisRoute", Caffeine.newBuilder().build());return map;}
}
到此其实基于redis的路由仓储service已经结束
基于zookeeper注册中心实现项目自动上报路由
为了实现动态路由,其实可以采用提供暴露接口的方式把相应的仓储接口提供出来,本示例提供的只是使用zk的监听机制,实现动态路由
关于zk的事件监听可以查看我的这篇文章:zookeeper相关操作
1、网关启动时添加zk监听事件
@Component
@Slf4j
@RequiredArgsConstructor
public class GatewayApplication implements ApplicationListener<ContextRefreshedEvent> {private final RouteDefinitionService routeDefinitionService;private final ZookeeperService zookeeperService;private final RouteProcesser routeProcesser;@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {//拉取网关配置routeDefinitionService.refreshRouteDefinition();log.info("<<<<<<<<<<刷新网关配置完成>>>>>>>>>>");zookeeperService.create(Constraint.ROUTE_DEFINITION, "init");zookeeperService.addWatchChildListener(Constraint.ROUTE_DEFINITION, routeProcesser);log.info("<<<<<<<<<<动态路由监听器配置完成>>>>>>>>>>");}
}
2、发布刷新事件:
public void refreshRouteDefinition() {this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));redisRouteRepository.getRouteDefinitions();}
3、 监听处理
/*** @classDesc: * @author: cyjer* @date: 2023/2/10 11:13*/
@Slf4j
@Component
@RequiredArgsConstructor
public class RouteProcesser extends AbstractChildListenerProcess implements ApiDefinitionConstraint {private static final String JTR = "/";private final static String ROUTE_CONFIG_ARGS_PREFIX = "_genkey_";private final RedisRouteRepository redisRouteRepository;private final RouteDefinitionService routeDefinitionService;@Overridepublic void process(CuratorFramework curatorFramework, PathChildrenCacheEvent cacheEvent) {ChildData data = cacheEvent.getData();if (Objects.nonNull(data) && cacheEvent.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {log.info("<<<<<<<<<<监听到动态路由变动申请>>>>>>>>>>");String content = new String(data.getData(), StandardCharsets.UTF_8);SiriusRouteDefinition siriusRouteDefinition = JSONObject.parseObject(content, SiriusRouteDefinition.class);RouteDefinition routeDefinition = new RouteDefinition();String serviceId = siriusRouteDefinition.getServiceId();routeDefinition.setId(serviceId);URI routeUri = UriComponentsBuilder.fromUriString("lb://" + serviceId).build().toUri();routeDefinition.setUri(routeUri);List<PredicateDefinition> predicates = getPredicates(JTR + serviceId + "/**");if (!predicates.isEmpty()) {routeDefinition.setPredicates(predicates);}// 获取过滤器List<FilterDefinition> filters = new ArrayList<>();Map<String, String> args = new LinkedHashMap<>();args.put(ROUTE_CONFIG_ARGS_PREFIX, "1");FilterDefinition filterDefinition = new FilterDefinition();filterDefinition.setName("StripPrefix");filterDefinition.setArgs(args);filters.add(filterDefinition);routeDefinition.setFilters(filters);redisRouteRepository.save(Mono.just(routeDefinition)).subscribe();routeDefinitionService.refreshRouteDefinition();log.info("<<<<<<<<<<刷新网关路由成功>>>>>>>>>>");}}/*** 获取地址断言** @param routePaths 路由地址* @return java.util.List*/private List<PredicateDefinition> getPredicates(String routePaths) {Map<String, String> args = new HashMap<>();String[] paths = routePaths.split(",");for (int i = 0; i < paths.length; i++) {args.put(ROUTE_CONFIG_ARGS_PREFIX + i, paths[i]);}PredicateDefinition predicate = new PredicateDefinition();predicate.setName("Path");predicate.setArgs(args);List<PredicateDefinition> predicates = new ArrayList<>();predicates.add(predicate);return predicates;}}
4、非网关的其他项目启动时注册路由
/*** @classDesc: 注册应用路由信息* @author: cyjer* @date: 2023/2/11 20:47*/
@Component
@Order(2)
@RequiredArgsConstructor
@Slf4j
public class ServiceRouteDefinitionReporter implements CommandLineRunner, Constraint {private final GatewayServiceProperties gatewayServiceProperties;private final ZookeeperService zookeeperService;@Overridepublic void run(String... args) throws Exception {String applicationName = apiDefinitionReporter.getApplicationName();siriusRouteDefinition.setServiceId(applicationName);siriusRouteDefinition.setGatewayId(gatewayServiceProperties.getGatewayId());zookeeperService.create(ROUTE_DEFINITION + SPLIT + applicationName, JSONObject.toJSONString(siriusRouteDefinition));zookeeperService.update(ROUTE_DEFINITION + SPLIT + applicationName, JSONObject.toJSONString(siriusRouteDefinition));log.info("<<<<< successfully reported route information >>>>>");}}
相关文章:
spring cloud gateway 实现redis动态路由及自动项目路由上报
前言 spring cloud gateway默认为内存存储策略,通过配置文件加载的方式生成路由定义信息 可以看到,RouteDefinitionRepository继承了两个父接口,分别为RouteDefinitionLocator和RouteDefinitionWriter,RouteDefinitionLocator定…...
c++函数对象(仿函数)、谓词、内建函数对象
1、函数对象 1.1 概念 重载函数调用操作符的类,这个类的对象就是函数对象,在使用这个函数对象对应使用重载的()符号时,行为类似于函数调用,因此这个函数也叫仿函数。 注意:函数对象࿰…...
物联网对供应链管理的影响
物联网对于许多行业来说都是一项革命性技术,其应用领域涉及零售、交通、金融、医疗保健和能源等行业。物联网在供应链等流程中已经展示了其深度的潜力。管理、预测和监督应用程序有助于车队运输经理提高配送的运营效率,并增加决策的准确性。如今…...
c++ 那些事 笔记
GitHub - Light-City/CPlusPlusThings: C那些事 1. ① extern extern关键字,C语言extern关键字用法详解 如果全局变量不在文件的开头定义,其有效的作用范围只限于其定义处到文件结束。如果在定义点之前的函数想引用该全局变量,则应该在…...
心跳机制Redis
进入命令传播阶段候,master与slave间需要进行信息交换,使用心跳机制进行维护,实现双方连接保持在线 master心跳: 指令:PING 周期:由repl-ping-slave-period决定,默认10秒 作用&#…...
蓝桥杯算法训练合集十七 1.数字反转2.试题39713.矮人采金子4.筛法5.机器指令
目录 1.数字反转 2.试题3971 3.矮人采金子 4.筛法 5.机器指令 1.数字反转 问题描述 给定一个整数,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零&…...
第一章 初识 Spring Security
第一章 初识 Spring Security 1、权限管理 权限管理 基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现了对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资…...
2023-02-20 关于回朔的思考
摘要: 考虑命运来回动荡交织,一些新的规划在不断的扩充, 而一些历史则开始陷入回朔。 有必要对历史和过往做一些规划和思考。 需要注意在这个阶段, 第一优先级是在反刍中将其最大化。 理论层: 一. 数据库的基础理论 ANSI SQL到词法解析和语法解析mysql的SQL层对…...
推荐系统[八]算法实践总结V1:淘宝逛逛and阿里飞猪个性化推荐:召回算法实践总结【冷启动召回、复购召回、用户行为召回等算法实战】
0.前言:召回排序流程策略算法简介 推荐可分为以下四个流程,分别是召回、粗排、精排以及重排: 召回是源头,在某种意义上决定着整个推荐的天花板;粗排是初筛,一般不会上复杂模型;精排是整个推荐环节的重中之重,在特征和模型上都会做的比较复杂;重排,一般是做打散或满足…...
适合初学者的超详细实用调试技巧(下)
我们日常写代码的时候,常常会遇到bug的情况,这个时候像我这样的初学者就会像无头苍蝇一样这里改改那里删删,调试的重要性也就显现出来,这篇文章接着上文来讲解。 上文地址:(8条消息) 适合初学者的超详细实用调试技巧&…...
C# String与StringBuilder 的区分
重点 1)它是比较的栈里面的值是否相等(值比较) 2)Equals它比较的是堆里面的值是否相等(引用地址值比较) 3)Object.ReferenceEquals(obj1,obj2)它是比较的是内存地址是否相等 问题描述: 今日提交代码时候,被检测工具发出修改建议。遂补充一下知识 1.什么…...
【麒麟】基于GPS北斗卫星技术的NTP网络时间服务器
【麒麟】基于GPS北斗卫星技术的NTP网络时间服务器 【麒麟】基于GPS北斗卫星技术的NTP网络时间服务器 麒麟系统NTP授时方案 设计思路: 在通用的麒麟服务器内部固定一块北斗卫星接收模块并引出卫星天线接口,卫星模块接收北斗卫星数据并解码输出时间数据&…...
“互联网+”下劳动关系认定的现状
1. 劳动关系的认定标准。依据目前我国法律的有关规定, 判定劳动关系存在两种情况:其一, 在有书面劳动合同的情况下, 这时应以书面合同作为认定标准;其二, 在没有书面合同的情况下, 则依据2005年劳社部的《关于确立劳动关系有关事项的通知》来认定, 其中第一条:“用人单位招用劳…...
LPWAN及高效弹性工业物联网核心技术方案
20多年前的一辆拖拉机就是一个纯机械的产品,里面可能并没有电子或者软件的构成;而随后随着软件的发展,拖拉机中嵌入了软件,它能控制发动机的功率及拖拉机防抱死系统;接下来,通过融入各种软件,拖…...
OPTIONS FMTSEARCH
FMTSEARCH 指定要检索的格式目录列表,语法如下:OPTIONS FMTSEARCH(catalog-specification-1<catalog-specification-2 … >);使用PROC FORMAT时可以定义格式目录,LIBRARYlibref或LIBRARYlibref.catalog。格式目录可以是libref或libref.…...
Python3 pip
Python3 pip pip 是 Python 包管理工具,该工具提供了对 Python 包的查找、下载、安装、卸载的功能。 软件包也可以在 https://pypi.org/ 中找到。 目前最新的 Python 版本已经预装了 pip。 注意:Python 2.7.9 或 Python 3.4 以上版本都自带 pip 工具…...
【2023-02-20】JS逆向之翼支付
提示:文章仅供参考,禁止用于非法途径 文章目录前言分析总结前言 真的好久没更了…… 提示:以下是本篇文章正文内容,下面案例可供参考 分析 进到网页,加载两个接口 applyLoginFactor 接口返回一个RSA公钥࿰…...
假如面试官问你Babel的原理该怎么回答
1. 什么是 Babel 简单地说,Babel 能够转译 ECMAScript 2015 的代码,使它在旧的浏览器或者环境中也能够运行。 // es2015 的 const 和 arrow function const add (a, b) > a b;// Babel 转译后 var add function add(a, b) {return a b; };Babel…...
深入Spring底层透析Bean创建过程之拨云见日篇
目录前言一.BeanFactory快速入门1. BeanFactory创建Bean2. BeanFactory和ApplicationContext的关系3. 和ApplicationContext区别(高频问点)4. BeanFactory的继承体系5. ApplicationContext的继承体系二.Bean实例化的基本流程(重点)前言 首先感谢您的阅览࿰…...
8 狗监控的封装
概述 为了保证嵌入式程序能够长时间稳定地运行,需要加入狗监控机制。狗监控的原理为:应用程序需要每隔一段时间来喂狗或保活,如果应用程序崩溃或者内核崩溃,导致长时间无法喂狗,则狗将超时,会自动重启系统。部分IPC芯片提供了硬件狗,对于没有硬件狗的,需要自行实现软件…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
