当前位置: 首页 > news >正文

如何使用Spring Cloud Gateway实现动态路由?

文章目录

      • 一、动态路由的核心原理
      • 二、基于 Nacos 实现动态路由(推荐)
        • 1. 环境准备
        • 2. 在 Nacos 中定义路由规则
        • 3. 配置动态路由刷新机制
        • 4. 测试动态路由
      • 三、基于数据库实现动态路由(自定义数据源)
        • 1. 数据库设计
        • 2. 自定义 RouteDefinitionLocator
        • 3. 定时刷新路由
      • 四、关键注意事项
      • 总结

在微服务场景中,服务实例可能频繁上下线,或需要动态调整路由规则(如灰度发布、临时路由),此时 动态路由(无需重启网关即可更新路由配置)就显得尤为重要。Spring Cloud Gateway 支持多种动态路由实现方式,核心思路是 将路由规则存储在外部数据源(如数据库、Nacos、Apollo 等),并通过事件监听或配置中心推送机制实时更新路由

一、动态路由的核心原理

Spring Cloud Gateway 的路由信息由 RouteDefinitionLocator 接口提供,默认从配置文件(application.yml)加载。要实现动态路由,需自定义 RouteDefinitionLocator 或通过事件刷新路由缓存

  1. 路由规则存储在外部数据源(如 Nacos);
  2. 网关启动时从数据源加载初始路由;
  3. 当数据源中的路由规则变更时,通过监听机制(如 Nacos 配置变更通知)触发路由刷新;
  4. 调用 Gateway 提供的 RouteDefinitionWriter 接口更新内存中的路由,并发布 RefreshRoutesEvent 事件通知网关重新加载路由。

二、基于 Nacos 实现动态路由(推荐)

Nacos 作为配置中心,支持配置变更实时推送,是实现动态路由的理想选择。以下是详细步骤:

1. 环境准备
  • 引入依赖(Maven):

    <!-- 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-config</artifactId>
    </dependency><!-- Nacos 服务发现(可选,用于服务名路由) -->
    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  • 配置 Nacos 地址(bootstrap.yml,需在 application.yml 之前加载):

    spring:application:name: gateway-service  # 服务名,对应 Nacos 配置的 Data IDcloud:nacos:config:server-addr: localhost:8848  # Nacos 服务器地址file-extension: yaml  # 配置文件格式
    
2. 在 Nacos 中定义路由规则

登录 Nacos 控制台(http://localhost:8848),创建配置:

  • Data IDgateway-service.yaml(与 spring.application.name 一致)
  • GroupDEFAULT_GROUP(默认)
  • 配置内容(标准的 Gateway 路由规则):
    spring:cloud:gateway:routes:- id: user-service-routeuri: lb://user-service  # 负载均衡到 user-service 服务predicates:- Path=/api/user/**filters:- StripPrefix=1  # 去除路径前缀 /api- id: order-service-routeuri: lb://order-servicepredicates:- Path=/api/order/**filters:- StripPrefix=1
    
3. 配置动态路由刷新机制

Nacos 配置变更时,会自动推送新配置到网关,需通过 @RefreshScope 使路由配置生效。但默认情况下,Gateway 不会自动刷新路由缓存,需自定义配置类监听配置变更并刷新路由:

import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosPropertySourceRepository;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
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.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.Executor;@Configuration
public class NacosDynamicRouteConfig implements ApplicationEventPublisherAware {@Autowiredprivate NacosConfigManager nacosConfigManager;@Autowiredprivate RouteDefinitionWriter routeDefinitionWriter;private ApplicationEventPublisher publisher;// 路由配置的 Data ID(与 Nacos 中一致)private static final String DATA_ID = "gateway-service.yaml";// 路由配置的 Groupprivate static final String GROUP = "DEFAULT_GROUP";@PostConstructpublic void init() throws NacosException {// 1. 初始化加载路由配置String configInfo = nacosConfigManager.getConfigService().getConfig(DATA_ID, GROUP, 5000);loadRouteConfig(configInfo);// 2. 监听 Nacos 配置变更nacosConfigManager.getConfigService().addListener(DATA_ID, GROUP, new Listener() {@Overridepublic void receiveConfigInfo(String configInfo) {// 配置变更时重新加载路由loadRouteConfig(configInfo);}@Overridepublic Executor getExecutor() {return null;}});}// 解析配置并更新路由private void loadRouteConfig(String configInfo) {try {// 从配置中解析出 RouteDefinition 列表(需自定义解析逻辑,或借助 Spring 配置绑定)List<RouteDefinition> routeDefinitions = parseRouteDefinitions(configInfo);// 先清空旧路由routeDefinitionWriter.delete(Mono.just("*")).block();// 再添加新路由if (!CollectionUtils.isEmpty(routeDefinitions)) {routeDefinitions.forEach(route -> {routeDefinitionWriter.save(Mono.just(route)).block();});}// 发布刷新事件,通知网关更新路由this.publisher.publishEvent(new RefreshRoutesEvent(this));} catch (Exception e) {e.printStackTrace();}}// 解析配置字符串为 RouteDefinition 列表(需根据实际配置格式实现)private List<RouteDefinition> parseRouteDefinitions(String configInfo) {// 示例:使用 Spring 的 YamlPropertiesFactoryBean 解析配置// 实际需根据 configInfo 中的内容提取 spring.cloud.gateway.routes 节点// 此处省略具体解析逻辑,可参考 Spring Cloud Gateway 的配置绑定方式return null;}@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.publisher = applicationEventPublisher;}
}

关键逻辑:

  • 初始化时从 Nacos 加载路由配置并添加到网关;
  • 监听 Nacos 配置变更,当路由规则更新时,先删除旧路由,再添加新路由,最后发布 RefreshRoutesEvent 事件触发网关刷新。
4. 测试动态路由
  1. 启动网关服务,验证初始路由是否生效(如访问 /api/user/1 能否转发到 user-service);
  2. 在 Nacos 控制台修改路由规则(如新增一个路由或修改路径),无需重启网关;
  3. 再次访问新路由,验证是否生效(如新增 /api/product/** 路由后,访问该路径能否转发到 product-service)。

三、基于数据库实现动态路由(自定义数据源)

若需更灵活的路由管理(如通过后台系统增删改路由),可将路由规则存储在数据库(如 MySQL),通过定时任务或事件监听刷新路由。

1. 数据库设计

创建路由规则表(gateway_route):

CREATE TABLE `gateway_route` (`id` varchar(64) NOT NULL COMMENT '路由ID',`uri` varchar(255) NOT NULL COMMENT '目标地址(如 lb://user-service)',`predicates` text COMMENT '断言规则(JSON格式,如 [{"name":"Path","args":{"pattern":"/api/user/**"}}])',`filters` text COMMENT '过滤器规则(JSON格式)',`order` int(11) DEFAULT 0 COMMENT '路由优先级(值越小越优先)',`status` tinyint(1) DEFAULT 1 COMMENT '状态(1-启用,0-禁用)',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 自定义 RouteDefinitionLocator

实现 RouteDefinitionLocator 接口,从数据库加载路由:

@Configuration
public class DbRouteDefinitionLocator implements RouteDefinitionLocator {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic Flux<RouteDefinition> getRouteDefinitions() {// 从数据库查询启用的路由List<RouteDefinition> routes = jdbcTemplate.query("SELECT id, uri, predicates, filters, `order` FROM gateway_route WHERE status = 1",(rs, rowNum) -> {RouteDefinition route = new RouteDefinition();route.setId(rs.getString("id"));route.setUri(URI.create(rs.getString("uri")));route.setOrder(rs.getInt("order"));// 解析断言(JSON -> List<PredicateDefinition>)String predicatesJson = rs.getString("predicates");List<PredicateDefinition> predicates = JSON.parseArray(predicatesJson, PredicateDefinition.class);route.setPredicates(predicates);// 解析过滤器(JSON -> List<FilterDefinition>)String filtersJson = rs.getString("filters");List<FilterDefinition> filters = JSON.parseArray(filtersJson, FilterDefinition.class);route.setFilters(filters);return route;});return Flux.fromIterable(routes);}
}
3. 定时刷新路由

通过定时任务定期从数据库加载最新路由并刷新:

@Component
public class DbRouteRefreshTask {@Autowiredprivate DbRouteDefinitionLocator dbRouteLocator;@Autowiredprivate RouteDefinitionWriter routeWriter;@Autowiredprivate ApplicationEventPublisher publisher;// 每30秒刷新一次@Scheduled(fixedRate = 30000)public void refreshRoutes() {try {// 清空旧路由routeWriter.delete(Mono.just("*")).block();// 加载新路由dbRouteLocator.getRouteDefinitions().collectList().block().forEach(route -> routeWriter.save(Mono.just(route)).block());// 发布刷新事件publisher.publishEvent(new RefreshRoutesEvent(this));} catch (Exception e) {e.printStackTrace();}}
}

四、关键注意事项

  1. 路由ID唯一性:确保路由 id 唯一,避免更新时冲突;
  2. 配置格式正确性:动态路由的断言(predicates)和过滤器(filters)格式需与 Gateway 要求一致,否则会加载失败;
  3. 性能考量:频繁刷新路由可能影响网关性能,建议合理设置刷新间隔(如 Nacos 推送机制可实时更新,无需定时任务);
  4. 容错处理:解析路由配置时需添加异常处理,避免单个路由配置错误导致整体路由失效。

总结

Spring Cloud Gateway 实现动态路由的核心是将路由规则从静态配置迁移到外部数据源,并通过事件机制实时刷新路由缓存。基于 Nacos 等配置中心的方案适合需要频繁调整路由的场景,而基于数据库的方案适合需要通过业务系统管理路由的场景。两种方式均可实现无需重启网关即可更新路由,提升微服务架构的灵活性和可维护性。

http://www.dtcms.com/a/540282.html

相关文章:

  • Linux Wlan 无线协议栈开发-传输层详解
  • 前端基础之《React(4)—webpack简介-编译打包优化》
  • F039 python五种算法美食推荐可视化大数据系统vue+flask前后端分离架构
  • 网站开发框架参考文献京东官方网上商城
  • Spring OXM:轻松实现Java-XML互转
  • 功能测试总结
  • 小白来学习 LVDS 差分原理及应用
  • 【Linux】网络层协议IP
  • 《Muduo网络库:TcpConnection类》
  • 网站详情页怎么做的好看的网页设计作品欣赏
  • 线扫相机上位机开发——如何提高问题排查效率
  • 计算机网络自顶向下方法10——应用层 HTTP/2 成帧 响应报文优先次序和服务器推
  • 孝感网站的建设网页设计一般一个月工资多少
  • 什么是持续集成(CI)和持续交付(CD)?测试在其中扮演什么角色?
  • 利用机器学习优化CPU调度的一些思路案例
  • Kafka 消息顺序消费深度解析:原理、实现方案与全局有序可行性分析
  • 数据结构初识,与算法复杂度
  • 网站色彩搭配中国纪检监察报社官网
  • (六)策略梯度算法 and Actor-Critic 框架
  • 基于萤火虫算法(FA)优化支持向量机(SVM)参数的分类实现
  • 【C++】C++11出来之后,到目前为止官方都做了些什么更新?
  • 公司网站建设及推广淮南网云小镇怎么样
  • UE C++ 离线安装 经验
  • Smart SVG Viewer,一款免费的SVG 图像查看器
  • 基於 MAC 的模型算力估算方法
  • VoxCPM macOS 安装部署
  • 【Linux篇】ELF文件与程序加载:理解链接过程中的静态库,动态库及目标文件
  • 做体育直播网站做数据权威的网站
  • 《因为独特》不畏惧与众不同 王宁泡泡玛特的独特之道:低风险创业的人性解码与产品设计指南
  • 【打靶日记】VulNyx 之 Lower3