spring-gateway 基于 nacos 配置文件的动态路由

简介: spring-gateway 基于 nacos 配置文件的动态路由

动态路由的实现方式多种多样,研究一下基于 nacos 配置文件形式的动态路由。


1. 创建项目,并pom.xml文件引入如下依赖

<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.olive</groupId>
 <artifactId>olive-gateway</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.7.1</version>
 </parent>
 <dependencyManagement>
  <dependencies>
   <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>2021.0.3</version>
    <type>pom</type>
    <scope>import</scope>
   </dependency>
   <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2021.1</version>
    <type>pom</type>
    <scope>import</scope>
   </dependency>
  </dependencies>
 </dependencyManagement>
 <dependencies>
  <dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-gateway</artifactId>
  </dependency>
  <dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  </dependency>
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>2.0.9</version>
  </dependency>
 </dependencies>
</project>

2. 增加一个配置类

主要配置 nacos 的 dataId 与 group

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "route.nacos")
public class GatewayConfig {
    private String dataId;
    private String group;
    private int timeout;
    //省略 getter  setter   
}


3.定义监听路由变化类

InFileRouteDefinitionRepository 类主要是简单 nacos 中的配置文件routes.json 的变化;只要监听到 routes.json 就进行路由更新。

import java.util.List;
import java.util.concurrent.Executor;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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 com.alibaba.fastjson.JSON;
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 com.alibaba.nacos.common.utils.CollectionUtils;
import com.olive.config.GatewayConfig;
import com.olive.route.model.GatewayRouteDO;
import reactor.core.publisher.Mono;
@Component
public class InFileRouteDefinitionRepository implements ApplicationEventPublisherAware{
    @Value("${spring.cloud.nacos.discovery.server-addr}")
    private String nacosServer;
    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    private ApplicationEventPublisher publisher;
    @Autowired
    private GatewayConfig gatewayConfig;
   @PostConstruct
   private void init() {
       dynamicRouteByListener(gatewayConfig.getDataId(), gatewayConfig.getGroup(), 
           nacosServer, gatewayConfig.getTimeout());
   }
    /**
     * 监听Nacos Server下发的动态路由配置
     */
    public void dynamicRouteByListener(String dataId, String group, String nacosServer, int timeout) {
        try {
            ConfigService configService = NacosFactory.createConfigService(nacosServer);
            String content = configService.getConfig(dataId, group, timeout);
            configService.addListener(dataId, group, new Listener() {
             @Override
                public void receiveConfigInfo(String configInfo) {
                    updateConfig(configInfo);
                }
                @Override
                public Executor getExecutor() {
                    return null;
                }
            });
            updateConfig(content);
        } catch (NacosException e) {
         e.printStackTrace();
        }
    }
    private void updateConfig(String configInfo) {
        try {
            GatewayRouteDO gatewayRouteDO = JSON.parseObject(configInfo, GatewayRouteDO.class);
            List<RouteDefinition> routeList = gatewayRouteDO.getRoutes();
            if (CollectionUtils.isNotEmpty(routeList)) {
                for (RouteDefinition routeDefinition : routeList) {
                    this.update(routeDefinition);
                }
            }
        } catch (Exception e) {
         e.printStackTrace();
        }
    }
    /**
     * 增加路由
     */
    public String add(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }
    /**
     * 更新路由
     */
    public String update(RouteDefinition definition) {
        try {
            this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
        } catch (Exception e) {
            return "update fail, not find route routeId: " + definition.getId();
        }
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
            return "success";
        } catch (Exception e) {
         e.printStackTrace();
            return "update route fail";
        }
    }
    /**
     * 删除路由
     */
    public String delete(String id) {
        try {
            this.routeDefinitionWriter.delete(Mono.just(id));
            return "delete success";
        } catch (Exception e) {
            e.printStackTrace();
            return "delete route fail";
        }
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}

4. 增加 application.yml 配置文件

server:
  port: 8089
spring:
  application:
    name: olive-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.255.10:8848
route:
  nacos:
    dataId: routes.json
    group: DEFAULT_GROUP
    timeout: 1000

需要在配置中心 nacos 增加 routes.json 配置文件;这个 json 文件的格式一定要符合 spring-gateway 的 route 格式;否则无法转换。routes.json 内容如下:

{
  "routes": [
    {
      "filters": [],
      "id": "pay_route",
      "order": 0,
      "predicates": [
        {
          "args": {
            "pattern": "/pay/**"
          },
          "name": "Path"
        }
      ],
      "uri": "lb://pay-service"
    },
    {
      "filters": [
        {
          "name": "RewritePath",
          "args": {
            "regexp": "/user/(?<remaining>.*)",
            "replacement": "/${remaining}"
          }
        }
      ],
      "id": "user_route",
      "order": 0,
      "predicates": [
        {
          "args": {
            "pattern": "/user/**"
          },
          "name": "Path"
        }
      ],
      "uri": "lb://user-center-service"
    }
  ]
}

5. 创建springboot 引导类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class GwApplication {
 public static void main(String[] args) {
   SpringApplication.run(GwApplication.class, args);
 }
}

测试验证只要通过在配置中心 nacos;修改 routes.json 配置文件即可。

相关文章
|
2月前
|
运维 监控 Java
nacos常见问题之获取配置文件的时候报错user not found如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
456 2
|
2月前
|
运维 Java API
nacos常见问题之Nacos读取配置文件失败如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
|
2月前
|
运维 Java Nacos
nacos常见问题之读取不到配置文件如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
476 2
|
4月前
|
XML Java 数据库
【Spring】SpringBoot 配置文件
【Spring】SpringBoot 配置文件
|
3月前
|
安全 Java 数据库连接
《Spring Boot配置文件大揭秘:看懂 application.yaml 与 bootstrap.yaml 的不同》
《Spring Boot配置文件大揭秘:看懂 application.yaml 与 bootstrap.yaml 的不同》
104 0
|
2月前
|
Java 数据库连接 API
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】
49 0
|
19天前
|
Java Shell 测试技术
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
35 0
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
|
2月前
|
缓存 Java 网络安全
Nacos报错问题之获取配置文件的时候报错如何解决
Nacos是一个开源的、易于部署的动态服务发现、配置管理和服务管理平台,旨在帮助微服务架构下的应用进行快速配置更新和服务治理;在实际运用中,用户可能会遇到各种报错,本合集将常见的Nacos报错问题进行归纳和解答,以便使用者能够快速定位和解决这些问题。
|
2月前
|
前端开发 Java 网络安全
nacos常见问题之Nacos获取配置文件时报错如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
|
2月前
|
存储 Cloud Native Java
深入比较Spring Cloud Nacos和Eureka的区别
【2月更文挑战第12天】
79 0