VDN 微服务架构搭建篇(三)基于 Nacos 的 Spring Cloud Gateway 动态路由管理

VDN 微服务架构搭建篇(三):基于 Nacos 的 Spring Cloud Gateway 动态路由管理

在微服务架构中,网关 是整个系统的入口,负责 流量管理、请求路由、安全控制等关键功能
Spring Cloud Gateway 作为 Spring 生态官方推荐的网关方案,具备 异步非阻塞 的高性能特性,并支持 动态路由、限流、负载均衡等功能

但在传统网关架构中,路由规则往往写死在配置文件中,每次修改都需要 手动调整配置 & 重启服务,这对于 高可用系统 来说并不友好。

本文将介绍如何使用 Spring Cloud Gateway + Nacos 配置中心 实现 动态路由管理,支持 自动发现、实时更新,让网关在运行时自动感知微服务变化,无需重启即可刷新路由规则,从而 提升微服务治理的灵活性和高可用性


一、Spring Cloud Gateway 基础配置

1.1 添加依赖

pom.xml 中引入 Spring Cloud Gateway 和 Nacos 相关依赖:

<dependencies><!-- Spring Cloud Gateway --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!-- Nacos 服务发现 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- Nacos 配置中心 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!-- Knife4j 网关文档 --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-gateway-spring-boot-starter</artifactId></dependency>
</dependencies>

1.2 在 Nacos 注册微服务

application.yml 配置 Nacos 相关信息,使服务可以自动注册到 Nacos:

spring:application:name: vdn-systemcloud:nacos:discovery:server-addr: 127.0.0.1:8848username: nacospassword: nacosgroup: vdnnamespace: dev17config:server-addr: ${spring.cloud.nacos.discovery.server-addr}username: ${spring.cloud.nacos.discovery.username}password: ${spring.cloud.nacos.discovery.password}namespace: ${spring.cloud.nacos.discovery.namespace}group: ${spring.cloud.nacos.discovery.group}file-extension: yaml

1.3 配置网关的静态路由

application.yml 中配置 静态路由(仅用于演示,后续会改为动态路由):

spring:cloud:gateway:routes:- id: vdn-systemuri: lb://vdn-systempredicates:- Path=/sys/**

二、Nacos 动态路由管理

2.1 在 Nacos 配置中心创建动态路由

(1)在 Nacos 控制台添加配置
  • Data ID: gateway-routes.json
  • Group: vdn
  • Namespace: dev17
  • 内容(JSON 格式):
[{"id": "vdn-system","uri": "lb://vdn-system","predicates": ["Path=/sys/**"]}
]
(2)在 bootstrap.yml 中添加以下配置
spring:application:name: vdn-gatewaycloud:nacos:discovery:# Nacos服务器地址server-addr: localhost:8848username: nacospassword: nacosgroup: vdn# Nacos命名空间namespace: dev17config:server-addr: ${spring.cloud.nacos.discovery.server-addr}username: ${spring.cloud.nacos.discovery.username}password: ${spring.cloud.nacos.discovery.password}namespace: ${spring.cloud.nacos.discovery.namespace}# 配置分组名称group: ${spring.cloud.nacos.discovery.group}# 文件扩展名,指示配置文件格式file-extension: yaml

2.2 监听 Nacos 变更 & 动态更新路由

NacosRouteDefinitionRepository 类中实现 监听 Nacos 变更,动态更新 Gateway 路由


import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** Nacos 动态路由管理* <p>* 该类用于管理 Spring Cloud Gateway 的路由,并将其存储在 Nacos 配置中心中。* 通过监听 Nacos 配置的变更,实现网关路由的动态刷新。*/
@Component
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {private final Logger log = LoggerFactory.getLogger(NacosRouteDefinitionRepository.class);// 用于发布 Spring 事件(刷新路由)private final ApplicationEventPublisher publisher;// Nacos 配置属性private final NacosConfigProperties nacosConfigProperties;// Nacos 配置管理器private final NacosConfigManager nacosConfigManager;// JSON 解析工具private final ObjectMapper objectMapper;// Nacos 中存储路由的 `dataId`private static final String DATA_ID = "gateway-routes.json";// 配置获取超时时间(单位:毫秒)private static final int CONFIG_TIMEOUT_MS = 3000;/*** 构造方法** @param publisher            Spring 事件发布器,用于动态刷新网关路由* @param nacosConfigProperties Nacos 配置属性*/@Autowiredpublic NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosConfigProperties nacosConfigProperties) {this.publisher = publisher;this.nacosConfigProperties = nacosConfigProperties;this.nacosConfigManager = new NacosConfigManager(nacosConfigProperties);this.objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);// 初始化 Nacos 配置监听器nacosListener();}/*** Nacos 配置监听器* <p>* 监听 Nacos 中 `gateway-routes.json` 发生变更时,触发 Gateway 重新加载路由。*/private void nacosListener() {// 使用单线程线程池,避免 Listener 需要 Executor 时出错ExecutorService executorService = Executors.newSingleThreadExecutor();try {nacosConfigManager.getConfigService().addListener(DATA_ID, nacosConfigProperties.getGroup(), new Listener() {@Overridepublic Executor getExecutor() {return executorService;}@Overridepublic void receiveConfigInfo(String configInfo) {log.info("收到新的路由配置: {}", configInfo);// 发布 Spring 事件,触发网关路由刷新publisher.publishEvent(new RefreshRoutesEvent(this));}});} catch (NacosException e) {log.error("Nacos 监听器初始化失败", e);} finally {// 关闭线程池,避免资源泄露executorService.shutdown();}}/*** 获取 Nacos 中的路由配置* <p>* 该方法会从 Nacos 读取 `gateway-routes.json` 配置,并解析为 RouteDefinition 列表。** @return 返回 Flux<RouteDefinition>,用于 Gateway 加载路由*/@Overridepublic Flux<RouteDefinition> getRouteDefinitions() {try {// 从 Nacos 读取配置String routeConfig = nacosConfigManager.getConfigService().getConfig(DATA_ID, nacosConfigProperties.getGroup(), CONFIG_TIMEOUT_MS);// 路由列表List<RouteDefinition> routeDefinitionList = new ArrayList<>();// 如果配置不为空,则解析 JSONif (StringUtils.hasText(routeConfig)) {routeDefinitionList = objectMapper.readValue(routeConfig, new TypeReference<>() {});}return Flux.fromIterable(routeDefinitionList);} catch (Exception e) {log.error("从 Nacos 获取路由定义失败", e);return Flux.error(e);}}/*** 保存路由定义* <p>* 该方法会将新的路由定义追加到 `gateway-routes.json` 中,并同步更新到 Nacos。** @param route 需要保存的路由定义* @return 返回 Mono<Void>*/@Overridepublic Mono<Void> save(Mono<RouteDefinition> route) {return route.flatMap(r -> {try {// 将新的 RouteDefinition 转换为 JSONString routeJson = objectMapper.writeValueAsString(r);// 发布到 NacosnacosConfigManager.getConfigService().publishConfig(DATA_ID, nacosConfigProperties.getGroup(), routeJson);return Mono.empty();} catch (Exception e) {log.error("保存路由定义失败", e);return Mono.error(e);}});}/**·* 删除路由定义* <p>* 该方法会从 `gateway-routes.json` 中移除指定的路由 ID,并同步更新 Nacos。** @param routeId 需要删除的路由 ID* @return 返回 Mono<Void>*/@Overridepublic Mono<Void> delete(Mono<String> routeId) {return routeId.flatMap(id -> {try {// 获取 Nacos 中的路由配置String routeConfig = nacosConfigManager.getConfigService().getConfig(DATA_ID, nacosConfigProperties.getGroup(), CONFIG_TIMEOUT_MS);// 解析 JSON 为 RouteDefinition 列表List<RouteDefinition> routeDefinitionList = objectMapper.readValue(routeConfig, new TypeReference<>() {});// 删除指定 ID 的路由routeDefinitionList.removeIf(rd -> rd.getId().equals(id));// 重新生成 JSON 并更新到 NacosString updatedRouteJson = objectMapper.writeValueAsString(routeDefinitionList);nacosConfigManager.getConfigService().publishConfig(DATA_ID, nacosConfigProperties.getGroup(), updatedRouteJson);return Mono.empty();} catch (Exception e) {log.error("删除路由定义失败,ID: {}", id, e);return Mono.error(e);}});}
}

三、总结

  1. 动态路由刷新:网关无需重启,即可自动刷新路由配置。
  2. 中心化管理:所有路由规则存储于 Nacos 配置中心,便于维护。
  3. 自动发现 & 负载均衡:结合 Nacos 注册中心,可自动发现新微服务并添加路由。

通过本文的介绍,你已经掌握了 如何基于 Spring Cloud Gateway + Nacos 实现动态路由管理 🎯。
你可以在项目中直接应用这个方案,让网关更智能、更高效! 🚀🚀🚀


写在最后

上一篇:👉 VDN 微服务架构搭建篇(二)服务注册与配置中心Nacos
下一篇:👉 待完善

源码🚀🚀🚀

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

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

相关文章

LLAMA-Factory安装教程(解决报错cannot allocate memory in static TLS block的问题)

步骤一&#xff1a; 下载基础镜像 # 配置docker DNS vi /etc/docker/daemon.json # daemon.json文件中 { "insecure-registries": ["https://swr.cn-east-317.qdrgznjszx.com"], "registry-mirrors": ["https://docker.mirrors.ustc.edu.c…

Java高频面试之SE-18

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; BIO NIO AIO的区别&#xff1f; 在 Java 网络编程中&#xff0c;BIO、NIO 和 AIO 是三种不同的 I/O 模型&#xff0c;它们的核心区别在于 阻塞…

蓝桥杯刷题DAY3:Horner 法则 前缀和+差分数组 贪心

所谓刷题&#xff0c;最重要的就是细心 &#x1f4cc; 题目描述 在 X 进制 中&#xff0c;每一数位的进制不固定。例如&#xff1a; 最低位 采用 2 进制&#xff0c;第二位 采用 10 进制&#xff0c;第三位 采用 8 进制&#xff0c; 则 X 进制数 321 的十进制值为&#xff…

BUU24 [GXYCTF2019]BabyUpload 1

开局上传文件 上传muma.php 上传.htaccess文件也被打回 再次求助互联网&#xff0c;才发现这提示给的多么明显&#xff0c;上传.htaccess文件是检查文件类型&#xff08;Contnet-Type&#xff09;&#xff0c;上传muma.php是检查后缀里头有没有ph &#xff0c;检查文件类型那…

RabbitMQ 从入门到精通:从工作模式到集群部署实战(三)

文章目录 使用CLI管理RabbitMQrabbitmqctlrabbitmq-queuesrabbitmq-diagnosticsrabbitmq-pluginsrabbitmq-streamsrabbitmq-upgraderabbitmqadmin 使用CLI管理RabbitMQ RabbitMQ CLI 工具需要安装兼容的 Erlang/OTP版本。 这些工具假定系统区域设置为 UTF-8&#xff08;例如en…

3.攻防世界 weak_auth

题目描述提示 是一个登录界面&#xff0c;需要密码登录 进入题目页面如下 弱口令密码爆破 用1 or 1 #试试 提示用admin登录 则尝试 用户名admin密码&#xff1a;123456 直接得到flag 常用弱口令密码&#xff08;可复制&#xff09; 用户名 admin admin-- admin or -- admin…

优化深度神经网络

训练集、开发集(验证集)、测试集 偏差与方差 正则化 L2正则 Dropout 随机丢弃部分神经元输入&#xff0c;经常用于计算机视觉的神经网络内&#xff0c;因为通常没有足够的训练数据&#xff0c;很容易出现过拟合的问题 数据增强 训练集规一化 可以使其图像更均匀&#xff0c;…

【玩转 Postman 接口测试与开发2_018】第14章:利用 Postman 初探 API 安全测试

《API Testing and Development with Postman》最新第二版封面 文章目录 第十四章 API 安全测试1 OWASP API 安全清单1.1 相关背景1.2 OWASP API 安全清单1.3 认证与授权1.4 破防的对象级授权&#xff08;Broken object-level authorization&#xff09;1.5 破防的属性级授权&a…

Spring @PropertySource:让你的应用配置更加模块化和可维护

PropertySource注解在Spring中的作用&#xff0c;就像是给Spring应用配了一个“外部配置箱”。 想象一下&#xff0c;你在开发一个Spring应用时&#xff0c;有很多配置信息需要设置&#xff0c;比如数据库的连接信息、应用的某些功能开关等。如果这些信息都硬编码在代码中&…

RK3576——USB3.2 OTG无法识别到USB设备

问题&#xff1a;使用硬盘接入到OTG接口无热插拔信息&#xff0c;接入DP显示屏无法正常识别到显示设备&#xff0c;但是能通过RKDdevTool工具烧录系统。 问题分析&#xff1a;由于热插拔功能实现是靠HUSB311芯片完成的&#xff0c;因此需要先确保HUSB311芯片驱动正常工作。 1. …

docker-compose 配置nginx

前言 前端打包的dist文件在宿主机&#xff0c;nginx运行在docker-compose 问题 nginx.conf 在本地配置可以生效&#xff0c;但是链接到容器就报错 基于本地的nginx运行&#xff0c;本地nginx.conf 如下 server {listen 8081;location / {root /usr/local/software/testweb/…

基于SpringBoot+ Vue的家教管理系统

随着互联网技术的发展&#xff0c;信息化管理已经深入到各个行业中。在教育领域&#xff0c;家教管理系统的需求日益增长。传统的手工管理方式在面对大量信息时&#xff0c;容易出现管理效率低下、数据错误率高、修改困难等问题。本文将介绍基于Spring Boot框架、MySQL数据库开…

【数据结构】树哈希

目录 一、树的同构1. 定义2. 具体理解(1) 结点对应(2) 孩子相同(3) 递归性质 3. 示例 二、树哈希1.定义2.哈希过程&#xff08;1&#xff09;叶节点哈希&#xff08;2&#xff09;非叶节点哈希&#xff08;3&#xff09;组合哈希值 3.性质&#xff08;1&#xff09; 唯一性 \re…

使用DeepSeek的技巧笔记

来源&#xff1a;新年逼自己一把&#xff0c;学会使用DeepSeek R1_哔哩哔哩_bilibili 前言 对于DeepSeek而言&#xff0c;我们不再需要那么多的提示词技巧&#xff0c;但还是要有两个注意点&#xff1a;你需要理解大语言模型的工作原理与局限,这能帮助你更好的知道AI可完成任务…

【工具篇】ChatGPT:开启人工智能新纪元

一、ChatGPT 是什么 最近,ChatGPT 可是火得一塌糊涂,不管是在科技圈、媒体界,还是咱们普通人的日常聊天里,都能听到它的大名。好多人都在讨论,这 ChatGPT 到底是个啥 “神器”,能让大家这么着迷?今天咱就好好唠唠。 ChatGPT,全称是 Chat Generative Pre-trained Trans…

【centOS】搭建公司内网git环境-GitLab 社区版(GitLab CE)

1. 安装必要的依赖 以 CentOS 7 系统为例&#xff0c;安装必要的依赖包&#xff1a; sudo yum install -y curl policycoreutils openssh-server openssh-clients postfix sudo systemctl start postfix sudo systemctl enable postfix2. 添加 GitLab 仓库 curl -sS https:/…

$route 和 $router 的区别是什么?

在 Vue Router 中,$route 和 $router 是两个不同的对象,它们各自承担着不同的角色。下面是它们的主要区别: 一、$route 定义$route 是当前路由的信息对象,包含了与当前路由相关的状态和参数。它是一个只读对象。 2. 主要属性 params:动态路由参数,例如 /user/:id 中的 …

node.js 08 express的使用和热重载nodemon的安装

一.express的安装和使用 安装 npm i express 使用 //引入express const express require(express)//启动服务器 const app express()//设置get请求地址&#xff0c;获取请求地址信息&#xff0c;和发送返回的数据 app.get(/bailan,(req, res) > {//req.query可以获取到客…

Python因为网络原因安装依赖库报错

现象 在终端运行以下指令 pip install pyautogui pillow keyboard 出现报错&#xff0c;终端信息如下&#xff1a; PS D:\code\Python> pip install pyautogui pillow keyboard Collecting pyautoguiUsing cached PyAutoGUI-0.9.54.tar.gz (61 kB)Installing build depe…

面试问题记录1

问题一&#xff1a;性能测试步骤 性能测试步骤主要包括以下几个阶段&#xff1a; ‌1. 需求分析阶段‌ 明确测试目标&#xff0c;了解性能测试需求&#xff0c;包括业务列表、性能指标、测试环境、数据量等详细需求‌12。熟悉项目相关的资源&#xff0c;如架构设计、软硬件环…