在Nacos官网中给出了手动监听Nacos配置变更的SDK:
所需依赖
XML<!--统一配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--加载bootstrap--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
nacos提供了监视配置文件的功能,当配置文件发生更改的能够实时推送到服务器,这个时候我们就能够获取最新的配置去做操作,比如与gateway进行配合实现动态路由,这里需要了解几个类和接口以及方法:
RouteDefinitionWriter :gateway提供的接口,用于动态的添加路由
NacosConfigManager :nacos提供的接口,用于与配置中心做交互
RouteDefinitionWriter:
RouteDefinitionWriter 是 Spring Cloud Gateway 提供的一个接口,用于动态地添加、更新和删除路由定义。它允许你在应用程序运行时修改网关的路由配置,而无需重启服务。
主要功能:
添加路由定义:
使用 save(Mono<RouteDefinition> route) 方法可以添加一个新的路由定义。
如果路由定义已经存在,则会更新该路由定义。
删除路由定义:
使用 delete(Mono<String> id) 方法可以根据路由ID删除一个路由定义。
更新路由定义:
通过 save(Mono<RouteDefinition> route) 方法可以更新现有的路由定义。
主要方法:
**save(Mono<RouteDefinition> route):**保存一个新的路由定义或更新现有的路由定义。
delete(Mono<String> id): 根据路由ID删除一个路由定义NacosConfigManager:
NacosConfigManager 是 Spring Cloud Alibaba Nacos 提供的一个配置管理器,用于与 Nacos 配置中心进行交互。它允许你在应用程序中方便地获取、监听和更新 Nacos 中的配置信息。
主要功能
**获取配置:**从 Nacos 配置中心获取指定 Data ID 和 Group 的配置信息。
**注册监听器:**为指定的配置项注册监听器,以便在配置发生变化时能够及时接收到通知并作出相应处理。
主要方法
**getConfigService():**获取 ConfigService 实例,用于执行具体的配置操作。
getConfig(String dataId, String group, long timeoutMs): 根据 Data ID 和 Group 获取配置信息,并设置超时时间。
**addListener(String dataId, String group, Listener listener):**为指定的配置项添加监听器。
removeListener(String dataId, String group, Listener listener): 移除指定的监听器。
实操
控制台示例
模板
根据上面的信息,下面就是代码案例,实际使用只需要修改id和group
javapackage com.hmall.gateway.route; import cn.hutool.json.JSONUtil; import com.alibaba.cloud.nacos.NacosConfigManager; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; import com.hmall.common.utils.CollUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.route.RouteDefinition; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; import javax.annotation.PostConstruct; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; /** * 动态路由加载器,用于从Nacos配置中心动态加载和更新路由配置 */ @Slf4j @Component @RequiredArgsConstructor public class DynamicRouteLoader { // 路由定义写入器,用于更新路由配置 private final RouteDefinitionWriter writer; // Nacos配置管理器,用于从Nacos获取配置信息 private final NacosConfigManager nacosConfigManager; // 路由配置文件的id和分组 private final String dataId = "gateway-routes.json"; private final String group = "DEFAULT_GROUP"; // 保存更新过的路由id private final Set<String> routeIds = new HashSet<>(); /** * 初始化路由配置监听器,启动时从Nacos拉取最新的路由配置并监听后续的配置变更 */ @PostConstruct // 在容器启动时执行 public void initRouteConfigListener() throws NacosException { // 1.注册监听器并首次拉取配置 String configInfo = nacosConfigManager.getConfigService() // 获取配置服务 .getConfigAndSignListener(dataId, group, 5000, new Listener() {// 监听器 @Override public Executor getExecutor() { // 线程池 return null; } /** * 配置信息变更时回调 * @param configInfo 返回的配置信息 */ @Override public void receiveConfigInfo(String configInfo) { // 配置信息变更时回调 updateConfigInfo(configInfo); } }); // 2.首次启动时,更新一次配置 updateConfigInfo(configInfo); } /** * 更新路由配置信息 * * @param configInfo 路由配置信息,JSON格式 */ private void updateConfigInfo(String configInfo) { log.debug("监听到路由配置变更,{}", configInfo); // 1.反序列化 List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class); // 2.更新前先清空旧路由 // 2.1.清除旧路由 for (String routeId : routeIds) { writer.delete(Mono.just(routeId)).subscribe(); } routeIds.clear(); // 2.2.判断是否有新的路由要更新 if (CollUtils.isEmpty(routeDefinitions)) { // 无新路由配置,直接结束 return; } // 3.更新路由 routeDefinitions.forEach(routeDefinition -> { // 3.1.更新路由 writer.save(Mono.just(routeDefinition)).subscribe(); //subscribe()用于异步执行,不阻塞当前线程 // 3.2.记录路由id,方便将来删除 routeIds.add(routeDefinition.getId()); }); } }
配置中心模板
java{ // 路由的唯一标识符 "id": "item", // 路由的匹配规则 "predicates": [ { // 使用 Path 匹配规则 "name": "Path", // 匹配的路径模式 "args": { // 匹配 /items/** 路径 "pattern1": "/items/**", // 匹配 /search/** 路径 "pattern2": "/search/**" } } ], // 路由的过滤器(当前没有过滤器) "filters": [], // 路由的目标服务地址,使用负载均衡 "uri": "lb://item-service" }
上面这一段就等同于是之前的这一段
javaspring: cloud: gateway: routes: - id: item uri: lb://item-service predicates: - Path=/items/**,/search/**
bootstrap.yaml
XMLspring: application: name: gateway # 服务名称 cloud: nacos: server-addr: localhost:8848 # nacos注册中心地址 config: file-extension: yaml # 配置文件后缀 shared-configs: # 共享配置 - data-id: shared-log.yaml # 日志配置文件