nacos-gateway动态路由

在Nacos官网中给出了手动监听Nacos配置变更的SDK:

Nacos Java 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进行配合实现动态路由,这里需要了解几个类和接口以及方法:

  1. RouteDefinitionWriter :gateway提供的接口,用于动态的添加路由

  2. 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

java 复制代码
package 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"
}

上面这一段就等同于是之前的这一段

java 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: item
          uri: lb://item-service
          predicates:
            - Path=/items/**,/search/**

bootstrap.yaml

XML 复制代码
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos注册中心地址
      config:
        file-extension: yaml # 配置文件后缀
        shared-configs: # 共享配置
          - data-id: shared-log.yaml # 日志配置文件

相关推荐
GISer_Jing3 分钟前
React中useState()钩子和函数式组件底层渲染流程详解
前端·react.js·前端框架
私人珍藏库1 小时前
Google Chrome-便携增强版[解压即用]
前端·chrome
基础不牢,地动山摇...2 小时前
tomcat核心组件及原理概述
java·tomcat
苏-言2 小时前
Maven全解析:从基础到精通的实战指南
java·maven
我的青春不太冷2 小时前
【实战篇章】深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据
运维·服务器·前端·学习
Anlici3 小时前
2025前端高频面试题--CSS篇
前端·css
追光少年33223 小时前
Learning Vue 读书笔记 Chapter 4
前端·javascript·vue.js
软件2053 小时前
【Vite + Vue + Ts 项目三个 tsconfig 文件】
前端·javascript·vue.js
程柯梦想3 小时前
Maven修改默认编码格式UTF-8
java·maven
涛ing3 小时前
【5. C++ 变量作用域及其深入探讨】
java·linux·c语言·开发语言·c++·ubuntu·vim