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;
    }
}

对应的 DO 类 ‍

import org.springframework.cloud.gateway.route.RouteDefinition;
import java.io.Serializable;
import java.util.List;
/**
 * 动态路由配置信息
 */
public class GatewayRouteDO implements Serializable{


 private List<RouteDefinition> routes;
 
  //TODO 省略getter  setter
}

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 配置文件即可。

记得点「」和「在看」↓

爱你们

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BUG弄潮儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值