SpringCloud系列教程(十二):网关配置动态路由

news2025/5/14 18:08:35

除了token以外,还有一个很实用的功能就是把网关的路由配置放到nacos上,并且修改路由配置的时候,网关服务可以动态的更新,这样我们在调整网络配置的时候,就不用重启服务了。所以我们需要用到两个重要的类:NacosConfigManager和RouteDefinitionWriter,NacosConfigManager用来监听nacos上配置的变化,RouteDefinitionWriter会执行路由配置。

1、将原来写在application.yml中的路由配置信息迁移到nacos上,dataId定义为gateway-routes,这里要注意,原来在项目中yml文件解析的时候,会被SpringCloud层层解析后生成RouteDefinition,在这期间SpringCloud会去解析比如Path=/api/*这种形式,但是现在我们要自己解析,就要改成符合RouteDefinition的完全形式,这是一个小难点。

spring:
  cloud:
    gateway:
      routes:
        - id: nacos-client-demo
          uri: lb://nacos-client-demo
          predicates: #断言,匹配访问的路径
            - name: Path
              args:
                pattern: /nacos-client-demo/api/**
          filters: # 过滤器
            - name: AddRequestHeader
              args:
                _genkey_0: headername
                _genkey_1: I am a header!
            - name: My
              args:
                _genkey_0: zhangsan
                _genkey_1: lisi
                _genkey_2: wangwu
        - id: open-feign-demo
          uri: lb://open-feign-demo
          predicates:
            - name: Path
              args:
                pattern: /open-feign-demo/api/**

2、在application.yml中添加nacos的配置信息就可以了,并且我特意添加了两个参数,用来指明动态路由配置的dataId,这样以后改成其他的也方便。

spring:
  main:
    # gateway组件中的spring-boot-starter-webflux和springboot作为web项目启动必不可少的spring-boot-starter-web出现冲突
    web-application-type: reactive
  application:
    name: gateway-demo
  cloud:
    gateway:
      nacos-data-id: gateway-routes
      nacos-group: devops
    nacos:
      server-addr: 192.168.3.54:80
      username: nacos
      password: nacos
      discovery:
        group: devops
        namespace: sit
      config:
        namespace: sit
        group: devops
  config:
    import: nacos:${spring.application.name}?refresh=true
server:
  port: 8888

3、定义一个component类DynamicRouterLoader,继承ApplicationEventPublisherAware,网上很多教程没有继承,因为版本不同,我用新版的发现必须要用ApplicationEventPublisherAware发布一下才能让路由信息生效。

package com.mj.gateway.router;

import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONUtil;
import cn.hutool.setting.yaml.YamlUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouterLoader implements ApplicationEventPublisherAware {
    //nacos配置管理器
    private final NacosConfigManager nacosConfigManager;
    //gateway路由规则写入器
    private final RouteDefinitionWriter writer;

    private ApplicationEventPublisher publisher;

    @Value("${spring.cloud.gateway.nacos-data-id:test}")
    private String dataId;
    @Value("${spring.cloud.gateway.nacos-group:test}")
    private String group;
    private final int timeout = 5000;

    //保存所有的路由id
    private final Set<String> routeIds = new HashSet<>();

    //PostConstruct表示实例化之后就会执行
    @PostConstruct
    public void initRouteConfigListener() throws NacosException {
        //获取配置,服务启动的时候就要加载一次配置
        String config = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, timeout, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }

            @Override
            public void receiveConfigInfo(String config) {
                //配置变化时,重新加载配置
                updateConfig(config);
            }
        });
        //服务启动,加载配置
        updateConfig(config);
    }

    private void updateConfig(String config) {
        log.info("更新路由信息");
        //读取nacos中yaml配置
        Dict dict = YamlUtil.load(new BufferedReader(new InputStreamReader(new ByteArrayInputStream(config.getBytes()))));
        //转换成Route对象
        List<RouteDefinition> routeDefinitions = JSONObject.parseObject(JSONUtil.toJsonStr(dict)).getJSONObject("spring").getJSONObject("cloud").getJSONObject("gateway").getJSONArray("routes").toList(RouteDefinition.class);
        //清理旧的路由规则
        routeIds.forEach(routeId -> writer.delete(Mono.just(routeId)).subscribe());
        //清空缓存
        routeIds.clear();
        // 遍历添加路由
        routeDefinitions.forEach(definition -> {
            //提交路由信息
            writer.save(Mono.just(definition)).subscribe();
            //缓存下记录,这样便于清除路由配置
            routeIds.add(definition.getId());
        });
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}

DynamicRouterLoader在服务启动的时候就会实例化并且注入spring中,所以我们给方法initRouteConfigListener添加注解@PostConstruct,这样实例化一完成就会执行该方法。方法里使用NacosConfigManager获取到nacos的数据并做一次更新路由,这次更新是用来启动服务时初始化路由配置,再添加一个监听器,每次nacos修改都会触发这个监听器再次更新路由配置。更新路由其实有两个思路,思路1是能准确判断每次修改、删除的路由信息,然后分别执行update和delete,这就需要我们去做新旧版本配置的区分工作了,工作量比较大,思路2就是每次都清空所有路由,然后把最新版配置信息加载进去。思路2更简单一点,不过我没有测试过路由信息特别大的情况下会不会导致延迟,通常我们的微服务不至于多到会产生延迟,但是这里依旧要警惕,工作中如果发现数量真的很大了,就要多做一些压力测试。

4、重启服务,做测试:http://127.0.0.1:8888/nacos-client-demo/api/login?userid=123&username=zhangsan

这时候是正常的:

5、修改一下nacos上路由信息,把nacos-client-demo的路由直接删掉,保存服务一直正常运行,观察是否生效。

如果debug能发现监听器被调用了,日志也会打印,再调用接口就已经404了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2310047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java-实现PDF合同模板填写内容并导出PDF文件

可用于公司用户合同导出pdf文件 效果图 一、导入所需要jar包 <!--生成PDF--><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.11</version></dependency><dependency&…

基于STM32的环境监测系统(自制蓝牙APP)

目录 项目概述 实物图 演示视频 概述 硬件模块 原理图以及PCB 0.96寸OLED屏幕&#xff08;SSD1306&#xff09; CubeMX配置 初始化代码 MQ-2烟雾传感器 CubeMX配置 初始化代码 DHT11温湿度模块 驱动代码 HC-05蓝牙模块 CubeMX配置 ​编辑 空闲中断回调函数 有…

月结保障:回滚慢、行锁频发

问题背景 3.1号月结现场保障&#xff0c;到场了先让kill了一个账务的会话&#xff0c;回滚了20min&#xff0c;巡检的时候发现报表库有几条行锁&#xff1a;enq: TX - row lock contention&#xff0c;sql&#xff1a;delete from table_name 语句已经失败&#xff0c;正在回滚…

Golang的微服务服务发现机制

## 1. Golang微服务服务发现机制 微服务架构已经成为当今软件开发的主流趋势&#xff0c;它能将复杂的单体应用拆分成小而独立的服务单元&#xff0c;实现更快的开发、部署和扩展。在微服务架构中&#xff0c;服务发现是非常重要的一环&#xff0c;它能够实现服务之间的自动发现…

Keepalived 入门详解:高可用集群部署最佳实践!

1. 什么是 Keepalived&#xff1f; 在分布式集群中&#xff0c;单点故障&#xff08;SPOF&#xff09; 是影响系统稳定性的重要问题。Keepalived 作为一款高可用服务软件&#xff0c;可以有效防止集群单点故障&#xff0c;保障系统的高可用性。 Keepalived 最初是为 LVS&#…

SparkStreaming之04:调优

SparkStreaming调优 一 、要点 4.1 SparkStreaming运行原理 深入理解 4.2 调优策略 4.2.1 调整BlockReceiver的数量 案例演示&#xff1a; object MultiReceiverNetworkWordCount {def main(args: Array[String]) {val sparkConf new SparkConf().setAppName("Networ…

开发博客系统

前言 准备工作 数据库表分为实体表和关系表 第一&#xff0c;建数据库表 然后导入前端页面 创建公共模块 就是统一返回值&#xff0c;异常那些东西 自己造一个自定义异常 普通类 mapper 获取全部博客 我们只需要返回id&#xff0c;title&#xff0c;content&#xff0c;us…

微信小程序上如何使用图形验证码

1、php服务器生成图片验证码的代码片段如下&#xff1a; 注意红框部分的代码&#xff0c;生成的是ArrayBuffer类型的二进制图片 2、显示验证码 显示验证码&#xff0c;不要直接image组件加上src显示&#xff0c;那样拿不到cookie&#xff0c;没有办法做图形验证码的验证&…

IntelliJ IDEA 构建项目时内存溢出问题

问题现象 在使用 IntelliJ IDEA 构建 Java 项目时&#xff0c;遇到了以下错误&#xff1a; java: java.lang.OutOfMemoryError: Java heap space java.lang.RuntimeException: java.lang.OutOfMemoryError: Java heap space这是一个典型的 Java 堆内存不足错误&#xff0c;表…

大模型微调与RAG检索增强技术深度解析

一、引言 随着人工智能技术的飞速发展&#xff0c;大模型&#xff08;如BERT、GPT等&#xff09;在自然语言处理、计算机视觉等领域取得了显著成效。然而&#xff0c;这些预训练好的大模型往往难以直接应用于特定业务场景&#xff0c;因此&#xff0c;大模型微调&#xff08;F…

[liorf_localization_imuPreintegration-2] process has died

使用liorf&#xff0c;编译没报错&#xff0c;但是roslaunch报错如下&#xff1a; 解决方法&#xff1a; step1: 如果你之前没有安装 GTSAM&#xff0c;可以尝试安装它 step2: 检查是否缺少依赖库 ldd /home/zz/1210/devel/lib/liorf_localization/liorf_localization_imuPr…

2024 年 MySQL 8.0.40 安装配置、Workbench汉化教程最简易(保姆级)

首先到官网上下载安装包&#xff1a;http://www.mysql.com 点击下载&#xff0c;拉到最下面&#xff0c;点击社区版下载 windows用户点击下面适用于windows的安装程序 点击下载&#xff0c;网络条件好可以点第一个&#xff0c;怕下着下着断了点第二个离线下载 双击下载好的安装…

【Python/Pytorch】-- 创建3090Ti显卡所需环境

文章目录 文章目录 01 服务器上&#xff0c;存在三个anaconda&#xff0c;如何选择合适的&#xff0c;创建python环境&#xff1f;02 conda、anaconda、cuda、cudnn区别03 用到一些指令04 如何指定cuda的版本&#xff1f;05 conda跟pip的区别&#xff1f;06 pycharm控制台07 服…

如何在无图形化界面的服务器上下载百度网盘的超大文件(10GB以上)?

目录 登录百度网盘账号 进入特定的文件夹 下载 完整教程 登录百度网盘账号 第一次登录的时候会展示&#xff1a; Please visit: https://openapi.baidu.com/oauth/2.0/authorize?client_idxxx And authorize this app Paste the Authorization Code here within 10 minut…

Linux磁盘情况查询

一、查询系统整体磁盘使用情况 1、基本语法 df -h 2、示例 二、查询指定目录的磁盘占用情况 1、基本语法 du -h 查询指定目录的磁盘占用情况&#xff0c;默认为当前目录 2、常用选项 选项 说明 -h 以人类可读的格式显示磁盘使用情况&#xff08;例如&#xff0c;KB、…

【3D格式转换SDK】HOOPS Exchange技术概览(二):3D数据处理高级功能

​ 在当今数字化工程领域&#xff0c;HOOPS Exchange作为一款强大的SDK&#xff0c;为3D工程应用程序的开发提供了关键支持。本文将深入剖析其基本组件、特定功能以及数据结构&#xff0c;带您全面了解这一驱动3D数据处理的核心工具。 一、概述 HOOPS Exchange专注于访问和重…

利用Adobe Acrobat 实现PPT中图片分辨率的提升

1. 下载适用于 Windows 的 64 位 Acrobat 注册方式参考&#xff1a;https://ca.whu.edu.cn/knowledge.html?type1 2. 将ppt中需要提高分辨率的图片复制粘贴到新建的pptx问价中&#xff0c;然后执行“文件—>导出---->创建PDF、XPS文档” 3. 我们会发现保存下来的distrib…

Elasticsearch:解锁深度匹配,运用Elasticsearch DSL构建闪电般的高效模糊搜索体验

目录 Elasticsearch查询分类 叶子查询 全文检索查询 match查询 multi_match查询 精确查询 term查询 range查询 复杂查询 bool查询简单应用 bool查询实现排序和分页 bool查询实现高亮 场景分析 问题思考 解决方案 search_after方案(推荐) point in time方案 方案…

解决局域网访问Dify却仅显示nginx页面的问题

为什么dify在本机可以正常访问&#xff0c;局域网通过ip访问却只看到欢迎使用nginx的提示&#xff0c;如果访问服务器ip/apps则直接提示404 Not Found。这是怎么回事该如何解决呢&#xff1f;文章中将一步步解决这些问题。 前言 之前在服务器部署了dify&#xff0c;也在服务器…

从小米汽车召回看智驾“命门”:智能化时代 — 时间就是安全

2025年1月&#xff0c;小米因车辆“授时同步异常”召回3万余辆小米SU7&#xff0c;成为其造车历程中的首个重大安全事件。 从小米SU7召回事件剖析&#xff0c;授时同步何以成为智能驾驶的命门&#xff1f; 2024年11月&#xff0c;多名车主反馈SU7标准版的智能泊车辅助功能出现…