Spring Cloud Gateway + Nacos 实现动态路由

news2025/1/24 11:24:13

1、maven 依赖

主要依赖
		<!-- 网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
案件差不多完整主要依赖
		<!--Spring boot 依赖(微服务基础)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <!--使用exclusions标签来标明要排除的包-->
            <!--排除logback-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--Web 服务相关-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 生成配置元数据,比如你平常在yml文件里面配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!--单元测试依赖,子工程中需要单元测试时,不需要再次引入此依赖了-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--bootstrap 相关-->
        <!--SpringBoot2.4.x之后默认不加载bootstrap.yml文件,需要在pom里加上依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
			<version>4.0.0</version>
        </dependency>
        
        <!--服务的注册和发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--lombok 依赖,子工程中假如需要lombok,不需要再引入-->
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>
        
		<!-- 网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

2、bootstrap.yml配置

server:
  port: 9999
  tomcat:
    max-http-form-post-size: -1
    max-threads: 500
    min-spare-threads: 50
  servlet:
    context-path: /
spring:
  main:
    web-application-type: reactive
     #当遇到同样名字的时候,是否允许覆盖注册
    allow-bean-definition-overriding: true 
  profiles:
    active: ${SYS_ENV:} # local:本地,dev:测试,uat:uat
  application:
    name: gateway-service
  cloud:
    nacos:
      # 配置中心#
      config:
        username: ${NACOS_USER:nacos}
        password: ${NACOS_PASSWORD:nacos}
        server-addr: ${NACOS_IP:nacos.com}:${NACOS_POST:8848}
        namespace: ${NACOS_NAMESPACE:}
        file-extension: yml
        refresh-enabled: true
        override-none: true  #本地配置优先
        shared-configs:
          - application.${spring.cloud.nacos.config.file-extension} # 配置文件名-Data Id
    # 路由网关配置
    gateway:
      # 启用了自动根据服务名建立路由
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true

# 动态路由配置
config:
  # 动态
  gateway-route:
    # nacos 配置dataId
    dataId: gateway-router
    # nacos服务地址
    server-addr: ${spring.cloud.nacos.config.server-addr}
    # 命名空间
    namespace: ${spring.cloud.nacos.config.namespace}
    # 账号密码
    username: ${spring.cloud.nacos.config.username}
    password: ${spring.cloud.nacos.config.password}

3、nacos 中心网关路由配置

nacos -  网关路由 配置截图

[
    {
        "id": "auth-service",
        "uri": "lb://auth-service",
        "predicates": [
            {
                "args": {
                    "pattern": "/auth-service/**"
                },
                "name": "Path"
            }
        ],
        "filters": [
            {
                "args": {
                    "parts": 1
                },
                "name": "StripPrefix"
            }
        ],
        "order": 1
    },
    {
        "id": "user-service",
        "uri": "lb://user-service",
        "predicates": [
            {
                "args": {
                    "pattern": "/user-service/**"
                },
                "name": "Path"
            }
        ],
        "filters": [
            {
                "args": {
                    "parts": 1
                },
                "name": "StripPrefix"
            }
        ],
        "order": 2
    }
]

4、配置文件 GatewayRouteConfig

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
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.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * 类描述:通过Nacos的配置动态更新网管路由
 * <pre>
 *     ApplicationEventPublisherAware 是由 Spring 提供的用于为 Service 注入 ApplicationEventPublisher 事件发布器的接口,使用这个接口,
 *     我们自己的 Service 就拥有了发布事件的能力。用户注册后,不再是显示地调用其他的业务 Service,而是发布一个用户注册事件。
 * </pre>
 *
 */
@Slf4j
@RefreshScope
@Component
public class GatewayRouteConfig implements ApplicationEventPublisherAware {
    /** 常量 */
    private static final String PROPERTIES_SERVER_ADDR = "serverAddr";
    private static final String PROPERTIES_NAMESPACE = "namespace";
    private static final String PROPERTIES_GROUP = "group";
    private static final String PROPERTIES_USERNAME = "username";
    private static final String PROPERTIES_PASSWORD = "password";

    /** nacos 配置dataId */
    @Value("${config.gateway-route.dataId:gateway-router}")
    private String dataId = "gateway-routes";

    /** nacos 配置group */
    @Value("${config.gateway-route.group:DEFAULT_GROUP}")
    private String group = "DEFAULT_GROUP";

    /** nacos 配置地址 */
    @Value("${config.gateway-route.server-addr}")
    private String serverAddr;

    /** nacos 命名空间 */
    @Value("${config.gateway-route.namespace}")
    private String namespace;

    /** nacos 账号 */
    @Value("${config.gateway-route.username}")
    private String username;

    /** nacos 密码 */
    @Value("${config.gateway-route.password}")
    private String password;


    /** 已加载的路由id集合 */
    private static final List<String> ROUTE_LIST = new ArrayList<>();

    private final RouteDefinitionWriter routeDefinitionWriter;

    /** 事件发布器 */
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 方法描述: 构造函数
     *
     * @param routeDefinitionWriter 路由定义写对象
     */
    public GatewayRouteConfig(RouteDefinitionWriter routeDefinitionWriter) {
        this.routeDefinitionWriter = routeDefinitionWriter;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 方法描述: 从Nacos的配置中加载动态路由
     *
     */
    @PostConstruct
    public void loadRouteFromNacosAndListener() {
        try {
            ConfigService configService = NacosFactory.createConfigService(getProperties());
            // 程序启动时调用Nacos的配置进行路由加载
            String initConfigInfo = configService.getConfig(dataId, group, 5000);
            addRouteAndPublish(initConfigInfo);

            // 添加监听路由变化
            addListener(configService);
        } catch (NacosException e) {
            log.error("加载路由配置错误,详情:", e);
        }
    }

    /**
     * 方法描述: 添加监听
     *
     * @param cs 配置服务对象
     */
    private void addListener(ConfigService cs) throws NacosException {
        // 添加监听
        cs.addListener(dataId, group, new Listener() {
            @Override
            public void receiveConfigInfo(String configInfo) {
                // 将监听到的路由加载到路由定义器中
                addRouteAndPublish(configInfo);
            }

            @Override
            public Executor getExecutor() {
                return null;
            }
        });
    }

    /**
     * 方法描述: Nacos配置属性
     *
     * @return {@link Properties}
     */
    private Properties getProperties() {
        Assert.notBlank(serverAddr, "Nacos的服务地址为空了!");
        Properties properties = new Properties();
        properties.put(PROPERTIES_SERVER_ADDR, serverAddr);
        if (StrUtil.isNotBlank(namespace)) {
            properties.put(PROPERTIES_NAMESPACE, namespace);
        }
        if (StrUtil.isNotBlank(group)) {
            properties.put(PROPERTIES_GROUP, group);
        }
        return properties;
    }

    /**
     * 添加并发布配置的路由
     *
     * @param configInfo 路由配置字符串;格式:JSON数组
     */
    private void addRouteAndPublish(String configInfo) {
        // 加载前需要清空有存在的路由
        clearRoute();
        // 解析从Nacos配置中读取的路由配置信息
        List<RouteDefinition> gatewayRouteDefinitions = JSONObject.parseArray(configInfo, RouteDefinition.class);
        for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
            // 将路由写到定义器中
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            // 将路由id加入内存集合中
            ROUTE_LIST.add(routeDefinition.getId());
        }

        // 刷新路由定义器
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }

    /**
     * 方法描述: 清空已存在的路由
     */
    private void clearRoute() {
        ROUTE_LIST.forEach(id -> this.routeDefinitionWriter.delete(Mono.just(id)).subscribe());
        ROUTE_LIST.clear();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1347082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLM之RAG实战(九)| 高级RAG 03:多文档RAG体系结构

在RAG&#xff08;检索和生成&#xff09;这样的框架内管理和处理多个文档有很大的挑战。关键不仅在于提取相关内容&#xff0c;还在于选择包含用户查询所寻求的信息的适当文档。基于用户查询对齐的多粒度特性&#xff0c;需要动态选择文档&#xff0c;本文将介绍结构化层次检索…

四种常见智能指针的介绍

一、介绍 当类中有指针成员时&#xff0c;一般有两种方式来管理指针成员&#xff1a;一是采用值型的方式管理&#xff0c;每个类对象都保留一份指针指向的对象的拷贝&#xff1b;另一种更优雅的方式是使用智能指针(smart pointer)&#xff0c;从而实现指针指向的对象的共享。 …

UDP协议基本原理

前言 本文主要讲解传输层中的UDP协议&#xff0c;我准备从UDP的特点出发&#xff0c;深入理解UDP协议&#xff0c;从UDP协议的结构推出UDP协议的特点&#xff1b; 一、理解端口号 前面我们总是说用IP加端口号的方式定位全网的唯一进程&#xff0c;通常在TCP/IP中&#xff0c;我…

gitee(码云)仓库内容更新,使用TortoiseGit同步本地仓库和远程仓库

前言&#xff1a; 网上有很多同步仓库教程&#xff0c;但都是git命令行操作。这篇使用TortoiseGit可视化操作同步本地仓库和远程仓库 克隆本地仓库&#xff0c;上传远程仓库&#xff0c;下载TortoiseGit可以看这篇使用gitee&#xff08;码云&#xff09;上传自己的代码&#xf…

电脑忘记开机密码很着急?一招搞定

前言 本教程适合没有登录微软账号的电脑哦&#xff5e; 随着手机越智能&#xff0c;人们花在电脑上的时间越来越少了。你家的电脑多久没开机了&#xff1f; 小伙伴有没有这样的经历&#xff1a;很久没有打开过电脑的你&#xff0c;突然有一天打开了电脑&#xff0c;却想不起…

继续声明 | 连声明都抄,谁抄袭谁,一目了然,现在竟然恬不知耻的反咬一口。

继续声明 | 连声明都抄&#xff0c;谁抄袭谁&#xff0c;一目了然&#xff0c;现在竟然恬不知耻的反咬一口。 一、本账号为《机器学习之心》博主CSDN唯一官方账号&#xff0c;唯一联系方式见文章底部。 二、《机器学习之心》博主未授权任何第三方账号进行模型合作、程序设计、…

harmonyOS Column组件通过space属性设置内部元素间距

例如 我们代码如下 import router from ohos.router Entry Component struct Index {build() {Row() {Column() {Text("年后")Text("一起")Text("旅游")}.width(100%)}.height(100%)} }运行之后 元素都粘连到一起 显然不太好看 我们就可以通过…

FPGA - 231227 - 5CSEMA5F31C6 - 电子万年历

TAG - F P G A 、 5 C S E M A 5 F 31 C 6 、电子万年历、 V e r i l o g FPGA、5CSEMA5F31C6、电子万年历、Verilog FPGA、5CSEMA5F31C6、电子万年历、Verilog 顶层模块 module TOP(input CLK,RST,inA,inB,inC,switch_alarm,output led,beep_led,output [41:0] dp );// 按键…

SaaS版Java基层健康卫生云HIS信息管理平台源码(springboot)

云his系统源码&#xff0c;系统采用主流成熟技术开发&#xff0c;B/S架构&#xff0c;软件结构简洁、代码规范易阅读&#xff0c;SaaS应用&#xff0c;全浏览器访问&#xff0c;前后端分离&#xff0c;多服务协同&#xff0c;服务可拆分&#xff0c;功能易扩展。多集团统一登录…

如何使用ModuleShifting测试Module Stomping和Module Overloading注入技术

关于ModuleShifting ModuleShifting是一款针对Module Stomping和Module Overloading注入技术的安全测试工具&#xff0c;该工具基于Python ctypes实现其功能&#xff0c;因此可以通过Python解释器或Pyramid在内存中完整执行&#xff0c;这样就可以避免使用编译加载器了。 需要…

Maya-UE xgen-UE 毛发导入UE流程整理

首先声明&#xff1a;maya建议用2022版本及一下&#xff0c;因为要用到Python 2 ,Maya2023以后默认是Python3不再支持Python2; 第一步&#xff1a;Xgen做好的毛发转成交互式Groom 第二步&#xff1a;导出刚生成的交互式Groom缓存&#xff0c;需要设置一下当前帧&#xff0c;和…

Python开源项目月排行 2023年12月

Python 趋势月报&#xff0c;按月浏览往期 GitHub,Gitee 等最热门的Python开源项目&#xff0c;入选的项目主要参考GitHub Trending,部分参考了Gitee和其他。排名不分先后&#xff0c;都是当前月份内相对热门的项目。 入选公式&#xff1d;70%GitHub Trending20%Gitee10%其他 …

UCi数据集处理技巧记录

如何起步使用UCI数据集 这里记录一下如何把带分号的数据变成经常使用的csv形式。这里使用wine的例子 https://archive.ics.uci.edu/dataset/186/winequality 原始数据 Wine UCI数据操作 这种带分号的使用python的不好阅读&#xff0c;可以尝试以下步骤&#xff1a; 转变为t…

c# listbox 添加图标和文字

给listbox 添加 DrawItem 事件 private void listBox1_DrawItem(object sender, DrawItemEventArgs e){int index e.Index;//获取当前要进行绘制的行的序号&#xff0c;从0开始。Graphics g e.Graphics;//获取Graphics对象。Rectangle bound e.Bounds;//获取当前要绘制的行的…

ppp会话建立的第二阶段:ppp认证

ppp认证的两种协议&#xff1a; pap 密码认证协议&#xff1a;是一种简单的明文认证&#xff0c;使用两次握手建立身份验证。如果碰到动态攻击&#xff0c;pap认证不会断开。一旦pap认证通过&#xff0c;就不会断开chap 挑战握手验证协议&#xff1a;通过三次握手的方式进行MD…

C/C++ 函数的默认参数

下面介绍一项新内容 - 默认参数。 默认参数指的是当函数调用中省略了实参时自动使用的一个值。 例如&#xff0c;如果将 void wow (int n)设置成n 有默认值为1&#xff0c;则函数调用 wow()相当于 wow(1)这极大地提高了使用函数的灵活性。 假设有一个名为left()的函数&#xff…

[Verilog] 加法器实现

1. 4位的加法器 先来一个最基本的的Verilog加法器 设计代码 module adder_4bit (input [3:0] a, b, output [3:0] sum, output carry);assign

arkts中@Watch监听的使用

概述 Watch用于监听状态变量的变化&#xff0c;当状态变量变化时&#xff0c;Watch的回调方法将被调用。Watch在ArkUI框架内部判断数值有无更新使用的是严格相等&#xff08;&#xff09;&#xff0c;遵循严格相等规范。当在严格相等为false的情况下&#xff0c;就会触发Watch的…

2024年【安全员-A证】考试内容及安全员-A证最新解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-A证考试内容参考答案及安全员-A证考试试题解析是安全生产模拟考试一点通题库老师及安全员-A证操作证已考过的学员汇总&#xff0c;相对有效帮助安全员-A证最新解析学员顺利通过考试。 1、【多选题】下列关于门…

Python序列之集合

系列文章目录 Python序列之列表Python序列之元组Python序列之字典Python序列之集合&#xff08;本篇文章&#xff09; Python序列之集合 系列文章目录前言一、集合是什么&#xff1f;二、集合的操作1.集合的创建&#xff08;1&#xff09;使用{}创建&#xff08;2&#xff09;…