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

devtools/2025/2/8 0:29:43/

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 路由

java">
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.ppmy.cn/devtools/156972.html

相关文章

ES6 变量解构赋值总结

1. 数组的解构赋值 1.1 基本用法 // 基本数组解构 const [a, b, c] [1, 2, 3]; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3// 跳过某些值 const [x, , y] [1, 2, 3]; console.log(x); // 1 console.log(y); // 3// 解构剩余元素 const [first, ...re…

音视频多媒体编解码器基础-codec

如果要从事编解码多媒体的工作&#xff0c;需要准备哪些更为基础的内容&#xff0c;这里帮你总结完。 因为数据类型不同所以编解码算法不同&#xff0c;分为图像、视频和音频三大类&#xff1b;因为流程不同&#xff0c;可以分为编码和解码两部分&#xff1b;因为编码器实现不…

25/2/6 <机器人基础> 运动学中各连杆的变换矩阵求法

变换矩阵 机器人通常包含多个关节和连杆&#xff0c;每个关节和连杆都有自己的局部坐标系。变换矩阵能够将一个点或向量从一个坐标系转换到另一个坐标系&#xff0c;从而实现对机器人各个部件位置和姿态的统一描述 变换矩阵能够将复杂的运动分解为旋转和平移的组合。通过矩阵乘…

2021.3.1的android studio版本就很好用

使用最新版的studio有个问题就是gradle版本也比较高&#xff0c;这样就容易出现之前项目不兼容问题&#xff0c;配置gradle可能会出现很多问题比较烦&#xff0c;所以干脆就用老版本的studio

langchain教程-2.prompt

前言 该系列教程的代码: https://github.com/shar-pen/Langchain-MiniTutorial 我主要参考 langchain 官方教程, 有选择性的记录了一下学习内容 这是教程清单 1.初试langchain2.prompt3.OutputParser/输出解析4.model/vllm模型部署和langchain调用5.DocumentLoader/多种文档…

【漫话机器学习系列】079.超参数调优(Hyperparameter Tuning)

超参数调优&#xff08;Hyperparameter Tuning&#xff09;是机器学习中优化模型性能的重要步骤之一。超参数是模型在训练之前设定的参数&#xff0c;而不是通过训练数据学习到的参数。正确地选择超参数可以显著提高模型的预测能力&#xff0c;反之&#xff0c;错误的超参数选择…

使用 CSS 实现透明效果

在 CSS 中&#xff0c;实现透明效果有几种方法&#xff0c;具体使用哪种方法取决于具体需求。以下是一些常见的方法&#xff1a; 使用 opacity 属性&#xff1a; opacity 属性可以设置整个元素的透明度&#xff0c;包括其所有的子元素。 .transparent { opacity: 0.5; /* 0 表…

基础相对薄弱怎么考研

复习总体规划 明确目标 选择专业和院校&#xff1a;根据你的兴趣、职业规划和自身实力&#xff0c;选择适合自己的专业和院校。可以参考往年的分数线、报录比、复试难度等。了解考试科目&#xff1a;不同专业考试科目不同&#xff0c;一般包括&#xff1a; 公共课&#xff1a…