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

相关推荐
天天进步20153 分钟前
Java全栈项目实战:校园报修服务系统
java·开发语言
Themberfue29 分钟前
Java 网络原理 ①-IO多路复用 || 自定义协议 || XML || JSON
xml·java·开发语言·网络·计算机网络·json
wm104334 分钟前
JavaEE 3大组件 Listener Servlet Filter
java·servlet·java-ee
疯一样的码农1 小时前
基于Spring Boot + Vue3实现的在线商品竞拍管理系统源码+文档
java·spring boot·后端
m0_748251352 小时前
【SpringBoot】日志文件
java·spring boot·spring
m0_748234712 小时前
Java-33 深入浅出 Spring - FactoryBean 和 BeanFactory BeanPostProcessor
java·开发语言·spring
知初~3 小时前
java相关学习文档或网站整理
java·开发语言·学习
码农小灰3 小时前
什么是缓存穿透、缓存击穿、缓存雪崩,在项目中是如何解决和预防?它们分别会带来什么危害?
java·缓存
a栋栋栋3 小时前
apifox
java·前端·javascript
A22743 小时前
Redis——数据淘汰策略
java·redis·缓存