Spring Cloud Gateway + Nacos 实现动态路由

本节开始介绍 SpringCloud Gateway 中动态路由的实现方法,包括:

Nacos 集成动态路由配置,更新配置文件即自动更新路由
MySQL + 二级缓存实现,主要基于 Gateway 的一些特性进行重写,实现路由信息的自动更新

这篇文章主要介绍第一种方式:将配置文件放到 Nacos 进行托管,网关服务通过引入 Nacos 而自动更新路由配置信息。实现较为简单。

本节代码在:https://github.com/laolunsi/spring-boot-examples,参考例 23 即可。

下面进入正题。

1. 创建网关服务

创建一个 springboot gateway 网关服务,默认是从 yaml 文件中读取 route 的配置。如果想要从 nacos 中读取配置,就要引入 nacos-config 的依赖,并设置配置文件的地址。

首先创建一个空 maven 项目 spring-cloud-gateway-nacos-routes ,声明 springboot 和 springcloud 的版本,并引入 nacos。

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.eknown</groupId>
    <artifactId>spring-cloud-gateway-nacos-routes</artifactId>
    <description>SpringCloud Gateway Nacos 动态路由示例</description>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR6</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

然后创建一个 springboot 项目,命名为:gateway-demo ,引入 gateway/nacos-config 等依赖:

<parent>
        <groupId>com.eknown</groupId>
        <artifactId>spring-cloud-gateway-nacos-routes</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <artifactId>gateway-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway-demo</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-core -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.3.9</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-config</artifactId>
            <version>0.9.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>

    </dependencies>

我们知道 SpringBoot 加载配置文件的顺序是:bootstrap.yml -> application.yml 这里需要将 nacos-config 的配置项放到 bootstrap.yml 中,这样项目启动时才能优先从 nacos 中加载配置信息。主要配置如下:

server:
  port: 8501

spring:
  application:
    name: gateway-demo
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        group: ${gateway.dynamicRoute.group}
        file-extension: json
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true
  redis:
    host: localhost
    password:
    port: 6379
    database: 10

# 自定义的配置项,用于设置路由信息所载的配置文件,比如这里是 group + dataId
gateway:
  dynamicRoute:
    enabled:  true
    dataType: nacos
    dataId: 'yq_routes'
    group: 'YQ_GATEWAY'

将自定义配置项加载到 Java 中:

@Configuration
public class GatewayConfig {

    public static String NACOS_DATA_ID;
    public static String NACOS_GROUP_ID;

    @Value("${gateway.dynamicRoute.dataId}")
    public void setNacosDataId(String dataId) {
        NACOS_DATA_ID = dataId;
    }

    @Value("${gateway.dynamicRoute.group}")
    public void setNacosGroupId(String group) {
        NACOS_GROUP_ID = group;
    }
}

下面我们重写一下 RouteDefinitionRepository 接口,将其改造成使用 Nacos 引入路由配置信息就可以了!

public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private static final Logger log = LoggerFactory.getLogger(NacosRouteDefinitionRepository.class);

    // 更新路由信息需要的
    private ApplicationEventPublisher publisher;

    // nacos 的配置信息
    private NacosConfigProperties nacosConfigProperties;

    // 构造器
    public NacosRouteDefinitionRepository(ApplicationEventPublisher publisher, NacosConfigProperties nacosConfigProperties) {
        this.publisher = publisher;
        this.nacosConfigProperties = nacosConfigProperties;
        System.out.println(GatewayConfig.NACOS_DATA_ID + ", " + GatewayConfig.NACOS_GROUP_ID);
        addListener();
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            String content = nacosConfigProperties.configServiceInstance()
                    .getConfig(GatewayConfig.NACOS_DATA_ID, GatewayConfig.NACOS_GROUP_ID,5000);
            List<RouteDefinition> routeDefinitions = getListByStr(content);
            return Flux.fromIterable(routeDefinitions);
        } catch (NacosException e) {
            log.error("getRouteDefinitions by nacos error", e);
        }
        return Flux.fromIterable(CollUtil.newArrayList());
    }

    /**
     * 添加Nacos监听
     */
    private void addListener() {
        try {
            nacosConfigProperties.configServiceInstance().addListener(GatewayConfig.NACOS_DATA_ID, GatewayConfig.NACOS_GROUP_ID, new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info("自动更新配置...\r\n" + configInfo);
                    publisher.publishEvent(new RefreshRoutesEvent(this));
                }
            });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    // 从 json 中解析出路由配置信息 —— 所以配置文件的格式一定要写对!
    private List<RouteDefinition> getListByStr(String content) {
        if (StrUtil.isNotEmpty(content)) {
            return JSONObject.parseArray(content, RouteDefinition.class);
        }
        return new ArrayList<>(0);
    }
}

最简单的方法是直接将这个 NacosRouteDefinitionRepository 类声明为 Bean。这里为了方便配置的切换写的复杂一点,通过 DynamicRouteConfig 来确认是否需要引入 nacos 的配置:

/**
 * 动态路由配置
 */
@Configuration
@ConditionalOnProperty(prefix = "gateway.dynamicRoute", name = "enabled", havingValue = "true")
public class DynamicRouteConfig {
    @Autowired
    private ApplicationEventPublisher publisher;

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

        @Bean
        public NacosRouteDefinitionRepository nacosRouteDefinitionRepository() {
            return new NacosRouteDefinitionRepository(publisher, nacosConfigProperties);
        }
    }
}

到这一步我们其实已经基本完成了 gateway + nacos 动态网关的实现了。下面我们测试一下。

2. 测试

创建一个简单的 springboot web 项目,引入 nacos 作为注册中心,并实现一个接口,比如:

server:
  port: 8502

spring:
  application:
    name: demo
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

注:这里实际上不需要引入 nacos 作为注册中心的,因为路由实际上就是一个转发功能,这个转发操作是由 gateway 提供的,而不是 nacos 提供的。。。

接口:

@RestController
@RequestMapping(value = "test")
public class TestAction {

    @GetMapping(value = "hello")
    public String hello(String name) {
        System.out.println("hello, " + name);
        return "hello, " + name;
    }
}

启动 nacos,添加配置文件,需要设置配置文件的 group 和 dataId 与上面的 gateway.dynamicRoute 中的配置相同。
内容示例:

[
  {
    "id": "demo",
    "uri": "lb://demo",
    "predicates": [
      {
        "name": "Path",
        "args": {
          "pattern": "/api/demo/**"
        }
      }
    ],
    "filters": [
      {
        "name": "StripPrefix",
        "args": {
          "parts": "2"
        }
      }
    ]
  }
]

启动 gateway-demo 以及 demo 项目,访问 gateway-demo 项目对应的路由地址,比如这里的:http://localhost:8501/api/demo/test/hello,如果运行正常,请求将被转发到 demo 项目的 /test/hello 接口,并返回对应的数据。

今天的分享就到这里啦!本来打算写一篇前文所说的第二种实现方法的文章的,不过由于二级缓存那边是用了组里封装的框架所以不便公布,后面有空我会自己实现一个基本的 demo,并同步到 Git 上!

水平有限,如有纰漏还请见谅。如果对文章内容有什么疑问,可以留言或直接联系我!thanks for your reading !

以上就是Spring Cloud Gateway + Nacos 实现动态路由的详细内容,更多关于SpringCloud Gateway 动态路由实现的资料请关注我们其它相关文章!

(0)

相关推荐

  • Springcloud GateWay网关配置过程图解

    一般为了不暴露自己的端口信息等,会选择架构一个网关在前面进行阻挡,起到保护的作用.附上一张工作示列图. 1.配置网关9527 gateway作为网关需要和其他的应用一样需要注册进eureka中进行管理,先创建应用gateway9527 pom文件,关键是gateway依赖 <dependencies> <dependency> <groupId>com.bai</groupId> <artifactId>cloud-api-common</

  • Spring Cloud Gateway全局通用异常处理的实现

    为什么需要全局异常处理 在传统 Spring Boot 应用中, 我们 @ControllerAdvice 来处理全局的异常,进行统一包装返回 // 摘至 spring cloud alibaba console 模块处理 @ControllerAdvice public class ConsoleExceptionHandler { @ExceptionHandler(AccessException.class) private ResponseEntity<String> handleAc

  • 详解SpringCloudGateway内存泄漏问题

    SpringCloudGateway内存泄漏问题 项目完善差不多,在进入压力测试阶段期间,发现了gateway有内存泄漏问题,问题发现的起因是,当时启动一台gateway,一台对应的下游应用服务,在压力测试期间,发现特别不稳定,并发量时高时低,而且会有施压机卡住的现象,然后找到容器对应的宿主机,并使用container stats命令观察内存,经过观察发现,压力测试时内存会暴涨,并由于超过限制最大内存导致容器挂掉(这里由于用的swarm所以会自动选择节点重启)最终发现由于之前测试服务器配置低,所

  • spring cloud gateway整合sentinel实现网关限流

    这篇文章主要介绍了spring cloud gateway整合sentinel实现网关限流,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 说明: sentinel可以作为各微服务的限流,也可以作为gateway网关的限流组件. spring cloud gateway有限流功能,但此处用sentinel来作为替待. 说明:sentinel流控可以放在gateway网关端,也可以放在各微服务端. 1,以父工程为基础,创建子工程 2,添加pom依赖

  • spring cloud gateway请求跨域问题解决方案

    这篇文章主要介绍了spring cloud gateway请求跨域问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下 @Configuration public class CorsConfig implements GlobalFilter, Ordered { private static final String ALL = "*"; private static final String MAX_AGE =

  • Spring Cloud Gateway不同频率限流的解决方案(每分钟,每小时,每天)

    SpringCloud Gateway 简介 SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式. SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuu

  • 基于Nacos实现Spring Cloud Gateway实现动态路由的方法

    简介 该文档主要介绍以Nacos为配置中心,实现Spring Cloud GateWay 实现动态路由的功能.Spring Cloud Gateway启动时候,就将路由配置和规则加载到内存里,无法做到不重启网关就可以动态的对应路由的配置和规则进行增加,修改和删除.通过nacos的配置下发的功能可以实现在不重启网关的情况下,实现动态路由. 集成 Spring Cloud GateWay集成 spring-cloud-starter-gateway:路由转发.请求过滤(权限校验.限流以及监控等) s

  • Spring Cloud Gateway重试机制原理解析

    重试,我相信大家并不陌生.在我们调用Http接口的时候,总会因为某种原因调用失败,这个时候我们可以通过重试的方式,来重新请求接口. 生活中这样的事例很多,比如打电话,对方正在通话中啊,信号不好啊等等原因,你总会打不通,当你第一次没打通之后,你会打第二次,第三次-第四次就通了. 重试也要注意应用场景,读数据的接口比较适合重试的场景,写数据的接口就需要注意接口的幂等性了.还有就是重试次数如果太多的话会导致请求量加倍,给后端造成更大的压力,设置合理的重试机制才是最关键的. 今天我们来简单的了解下Spr

  • Spring Cloud Gateway + Nacos 实现动态路由

    本节开始介绍 SpringCloud Gateway 中动态路由的实现方法,包括: Nacos 集成动态路由配置,更新配置文件即自动更新路由 MySQL + 二级缓存实现,主要基于 Gateway 的一些特性进行重写,实现路由信息的自动更新 这篇文章主要介绍第一种方式:将配置文件放到 Nacos 进行托管,网关服务通过引入 Nacos 而自动更新路由配置信息.实现较为简单. 本节代码在:https://github.com/laolunsi/spring-boot-examples,参考例 23

  • Spring Cloud 网关服务 zuul 动态路由的实现方法

    zuul动态路由 网关服务是流量的唯一入口.不能随便停服务.所以动态路由就显得尤为必要. 数据库动态路由基于事件刷新机制热修改zuul的路由属性. DiscoveryClientRouteLocator 可以看到DiscoveryClientRouteLocator 是默认的刷新的核心处理类. //重新加载路由信息方法 protected方法.需要子方法重新方法. protected LinkedHashMap<String, ZuulRoute> locateRoutes() //触发刷新的

  • Spring Cloud 整合 nacos实现动态配置中心的详细步骤

    目录 前提条件 整合步骤 1. 添加依赖 2. 新建 nacos 配置 3. bootstrap.properties 配置 4. 配置dataId 4.1 自动配置 dataId 4.2 手动设置 dataId 5.获取数据 总结 源码 参考文献 上一篇文章讲解了Spring Cloud 整合 nacos 实现服务注册与发现,nacos除了有服务注册与发现的功能,还有提供动态配置服务的功能.本文主要讲解Spring Cloud 整合nacos实现动态配置服务.主要参考官方部署手册点我. 前提条

  • Spring Cloud Gateway入门解读

    Spring Cloud Gateway介绍 前段时间刚刚发布了Spring Boot 2正式版,Spring Cloud Gateway基于Spring Boot 2,是Spring Cloud的全新项目,该项目提供了一个构建在Spring 生态之上的API网关,包括:Spring 5,Spring Boot 2和Project Reactor. Spring Cloud Gateway旨在提供一种简单而有效的途径来发送API,并为他们提供横切关注点,例如:安全性,监控/指标和弹性.当前最新的

  • spring cloud gateway 如何修改请求路径Path

    一.背景 项目升级改造,老项目使用请求url中特定参数进行服务路由,现使用gateway网关进行路由服务信息 二.根据参数信息修改请求路径Path @Component public class RequestFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpR

  • Nacos+Spring Cloud Gateway动态路由配置实现步骤

    目录 前言 一.Nacos环境准备 1.启动Nacos配置中心并创建路由配置 2.连接Nacos配置中心 二.项目构建 1.项目结构 2.编写测试代码 三.测试动态网关配置 1.启动服务,观察注册中心 2.访问网关,观察服务日志 四.总结 前言 Nacos最近项目一直在使用,其简单灵活,支持更细粒度的命令空间,分组等为麻烦复杂的环境切换提供了方便:同时也很好支持动态路由的配置,只需要简单的几步即可.在国产的注册中心.配置中心中比较突出,容易上手,本文通过gateway.nacos-consume

  • Spring Cloud Gateway动态路由Apollo实现详解

    目录 背景 路由的加载 实现动态路由 背景 在之前我们了解的Spring Cloud Gateway配置路由方式有两种方式 通过配置文件 spring: cloud: gateway: routes: - id: test predicates: - Path=/ms/test/* filters: - StripPrefix=2 uri: http://localhost:9000 通过JavaBean @Bean public RouteLocator routeLocator(RouteL

  • 详解Spring Cloud Gateway基于服务发现的默认路由规则

    1.Spring Gateway概述 1.1 什么是Spring Cloud Gateway Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式.Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代Netflix ZUUL,其不仅提供统一的路由

  • 详解Spring Cloud Gateway 数据库存储路由信息的扩展方案

    动态路由背景 ​ 无论你在使用Zuul还是Spring Cloud Gateway 的时候,官方文档提供的方案总是基于配置文件配置的方式 例如: # zuul 的配置形式 routes: pig-auth: path: /auth/** serviceId: pig-auth stripPrefix: true # gateway 的配置形式 routes: - id: pigx-auth uri: lb://pigx-auth predicates: - Path=/auth/** filte

随机推荐