Spring Cloud Zuul的动态路由怎样做?集成Nacos实现很简单

简介: 网关的核心概念就是路由配置和路由规则,而作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,是尽量要避免重启的,所以实现动态路由是非常有必要的;本文主要介绍实现的思路,并且以Nacos为数据源来讲解。

动态路由.jpg

一、说明

网关的核心概念就是路由配置和路由规则,而作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,是尽量要避免重启的,所以实现动态路由是非常有必要的;本文主要介绍实现的思路,并且以Nacos为数据源来讲解

 

二、实现要点

要实现动态路由只需关注下面4个点

  1. 网关启动时,动态路由的数据怎样加载进来
  2. 静态路由动态路由以那个为准,ps:静态路由指的是配置文件里写死的路由配置
  3. 监听动态路由的数据源变化
  4. 数据有变化时怎样通知zuul刷新路由

 

三、具体实现

3.1. 实现动态路由的数据加载

  • 重写SimpleRouteLocator类的locateRoutes方法,此方法是加载路由配置的,父类中是获取properties中的路由配置,可以通过扩展此方法,达到动态获取配置的目的
  • 这里采用静态路由动态路由共存,相同路由id以动态路由优先覆盖的实现方式

AbstractDynRouteLocator类可查看:

public abstract class AbstractDynRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
    private ZuulProperties properties;

    public AbstractDynRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
        this.properties = properties;
    }

    /**
     * 刷新路由
     */
    @Override
    public void refresh() {
        doRefresh();
    }

    @Override
    protected Map<String, ZuulRoute> locateRoutes() {
        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
        // 从application.properties中加载静态路由信息
        routesMap.putAll(super.locateRoutes());
        // 从数据源中加载动态路由信息
        routesMap.putAll(loadDynamicRoute());
        // 优化一下配置
        LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
        for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
            String path = entry.getKey();
            // Prepend with slash if not already present.
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
            if (StringUtils.hasText(this.properties.getPrefix())) {
                path = this.properties.getPrefix() + path;
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            }
            values.put(path, entry.getValue());
        }
        return values;
    }

    /**
     * 加载路由配置,由子类去实现
     */
    public abstract Map<String, ZuulRoute> loadDynamicRoute();
}
由于动态路由的数据可以有很多种 途径,如:Nacos、Redis、Zookeeper、DB等,所以这里定义一个抽象类,由具体的实现类去定义 loadDynamicRoute方法

3.2. Nacos路由实现类

NacosDynRouteLocator类完整的代码实现可查看:

3.2.1. 实现loadDynamicRoute方法获取动态数据

    @Override
    public Map<String, ZuulProperties.ZuulRoute> loadDynamicRoute() {
        Map<String, ZuulRoute> routes = new LinkedHashMap<>();
        if (zuulRouteEntities == null) {
            zuulRouteEntities = getNacosConfig();
        }
        for (ZuulRouteEntity result : zuulRouteEntities) {
            if (StrUtil.isBlank(result.getPath()) || !result.isEnabled()) {
                continue;
            }
            ZuulRoute zuulRoute = new ZuulRoute();
            BeanUtil.copyProperties(result, zuulRoute);
            routes.put(zuulRoute.getPath(), zuulRoute);
        }
        return routes;
    }
        
    private List<ZuulRouteEntity> getNacosConfig() {
        try {
            String content = nacosConfigProperties.configServiceInstance().getConfig(ZUUL_DATA_ID, ZUUL_GROUP_ID,5000);
            return getListByStr(content);
        } catch (NacosException e) {
            log.error("listenerNacos-error", e);
        }
        return new ArrayList<>(0);
    }

3.2.2. 增加NacosListener监听路由数据变化

    private void addListener() {
        try {
            nacosConfigProperties.configServiceInstance().addListener(ZUUL_DATA_ID, ZUUL_GROUP_ID, new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    //赋值路由信息
                    locator.setZuulRouteEntities(getListByStr(configInfo));
                    RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(locator);
                    publisher.publishEvent(routesRefreshedEvent);
                }
            });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }
注意路由数据变化后不需要自己手动刷新路由,只需要给 zuul发送一个 RoutesRefreshedEvent事件即可, zuul自己有个 ZuulRefreshListener类会监听事件帮我们刷新路由

3.3. 配置类创建NacosDynRouteLocator的Bean

DynamicZuulRouteConfig可查看:

@Configuration
@ConditionalOnProperty(prefix = "zlt.gateway.dynamicRoute", name = "enabled", havingValue = "true")
public class DynamicZuulRouteConfig {
    @Autowired
    private ZuulProperties zuulProperties;

    @Autowired
    private DispatcherServletPath dispatcherServletPath;

    /**
     * Nacos实现方式
     */
    @Configuration
    @ConditionalOnProperty(prefix = "zlt.gateway.dynamicRoute", name = "dataType", havingValue = "nacos", matchIfMissing = true)
    public class NacosZuulRoute {
        @Autowired
        private NacosConfigProperties nacosConfigProperties;

        @Autowired
        private ApplicationEventPublisher publisher;

        @Bean
        public NacosDynRouteLocator nacosDynRouteLocator() {
            return new NacosDynRouteLocator(nacosConfigProperties, publisher, dispatcherServletPath.getPrefix(), zuulProperties);
        }
    }
}
这里通过自定义配置来控制是否开启 动态路由功能

3.4. 添加Nacos路由配置

nacos配置.png

新增配置项:

  • Data Id:zuul-routes
  • Group:ZUUL_GATEWAY
  • 配置内容:
[
    {
        "enabled":true,
        "id":"csdn",
        "path":"/csdn/**",
        "retryable":false,
        "stripPrefix":true,
        "url":"https://www.csdn.net/"
    }, {
        "enabled":true,
        "id":"github",
        "path":"/github/**",
        "retryable":false,
        "stripPrefix":true,
        "url":"http://github.com/"
    }
]
添加两条路由数据

 

四、测试

  • 启动网关通过/actuator/routes端点查看当前路由信息

路由2.png

可以看到静态路由和 Nacos里配置的两条路由信息并存显示
  • 修改Nacos配置,关闭csdn路由

nacos配置_关闭csdn.png

  • 刷新查看网关的路由信息

路由3.png

csdn的路由已经看不到了,实现了动态改变路由配置
目录
相关文章
|
12天前
|
缓存 供应链 物联网
如何将 Salesforce IoT Cloud 与其他系统集成
Salesforce IoT Cloud 可通过其开放的 API 和集成云平台轻松与外部系统集成,实现数据交换和流程自动化,支持多种协议和标准,帮助企业构建智能物联网应用。
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
158 1
|
1月前
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用
|
25天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
97 62
|
1月前
|
IDE API 开发工具
沉浸式集成阿里云 OpenAPI|Alibaba Cloud API Toolkit for VS Code
Alibaba Cloud API Toolkit for VSCode 是集成了 OpenAPI 开发者门户多项功能的 VSCode 插件,开发者可以通过这个插件方便地查找API文档、进行API调试、插入SDK代码,并配置基础环境设置。我们的目标是缩短开发者在门户和IDE之间的频繁切换,实现API信息和开发流程的无缝结合,让开发者的工作变得更加高效和紧密。
沉浸式集成阿里云 OpenAPI|Alibaba Cloud API Toolkit for VS Code
|
23天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
41 2
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第8天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建并配置 Spring Boot 项目,实现后端 API 和安全配置。接着,使用 Ant Design Pro Vue 脚手架创建前端项目,配置动态路由和菜单,并创建相应的页面组件。最后,通过具体实践心得,分享了版本兼容性、安全性、性能调优等注意事项,帮助读者快速搭建高效且易维护的应用框架。
44 3
|
1月前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
109 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用
【10月更文挑战第7天】本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,通过 Spring Initializr 创建 Spring Boot 项目并配置 Spring Security。接着,实现后端 API 以提供菜单数据。在前端部分,使用 Ant Design Pro Vue 脚手架创建项目,并配置动态路由和菜单。最后,启动前后端服务,实现高效、美观且功能强大的应用框架。
45 2
|
1月前
|
存储 前端开发 Java
Spring Boot 集成 MinIO 与 KKFile 实现文件预览功能
本文详细介绍如何在Spring Boot项目中集成MinIO对象存储系统与KKFileView文件预览工具,实现文件上传及在线预览功能。首先搭建MinIO服务器,并在Spring Boot中配置MinIO SDK进行文件管理;接着通过KKFileView提供文件预览服务,最终实现文档管理系统的高效文件处理能力。
303 11
下一篇
无影云桌面