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 # 日志配置文件

相关推荐
gnip6 分钟前
浏览器跨标签页通信方案详解
前端·javascript
现在,此刻11 分钟前
leetcode 11. 盛最多水的容器 -java
java·算法·leetcode
gnip38 分钟前
运行时模块批量导入
前端·javascript
DKPT40 分钟前
Java设计模式之开闭原则介绍与说明
java·设计模式·开闭原则
hyy27952276841 小时前
企业级WEB应用服务器TOMCAT
java·前端·tomcat
布朗克1681 小时前
Spring Boot项目通过Feign调用三方接口的详细教程
java·spring boot·feign
逆风优雅1 小时前
vue实现模拟 ai 对话功能
前端·javascript·html
Arva .1 小时前
Spring基于XML的自动装配
xml·java·spring
若梦plus1 小时前
http基于websocket协议通信分析
前端·网络协议
不羁。。2 小时前
【web站点安全开发】任务3:网页开发的骨架HTML与美容术CSS
前端·css·html