基于nacos实现Spring cloud Gateway动态路由的方法


theme: juejin

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

简介:该文章主要介绍以Nacos为注册、配置中心,实现Spring Cloud GateWay 动态路由的功能。Spring Cloud Gateway启动时候,就将通过路由配置和规则加载到内存里,无法做到不重启网关就可以动态的对应路由的配置和规则进行增加,修改和删除。通过nacos的配置下发的功能可以实现在不重启网关的情况下,实现动态路由的效果

项目介绍

网关 service-gateway

pom 介绍:

`<?xml version="1.0" encoding="UTF-8"?>


startagaincloud
org.example
1.0

4.0.0

<artifactId>service-gateway</artifactId>

<dependencies>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>service-common</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

    <!-- 该spring-boot-starter-actuator依赖提供了很多监控所需的接口,也是必须引入的 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!--<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>


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

    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-client</artifactId>
        <version>2.3.0</version>
    </dependency>

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

    <!--elk依赖  -->
    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
    </dependency>

</dependencies>

`

启动类:

`
@EnableFeignClients(basePackages = {“com.mlc.cloud.start”})
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
public class GatewayApplication {

public static void main(String[] args) {
    SpringApplication.run(GatewayApplication.class,args);
}

}

` 关键的实现动态路由逻辑代码

`/**

  • 动态更新路由网关service

  • 1)实现一个Spring提供的事件推送接口ApplicationEventPublisherAware

  • 2)提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
    */
    @Slf4j
    @Service
    public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    /**

    • 发布事件
      */
      @Autowired
      private ApplicationEventPublisher publisher;

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

    /**

    • 删除路由
    • @param id
    • @return
      /
      public String delete(String id) {
      try {
      log.info(“gateway delete route id {}”,id);
      this.routeDefinitionWriter.delete(Mono.just(id));
      return “delete success”;
      } catch (Exception e) {
      return “delete fail”;
      }
      }
      /
      *
    • 更新路由
    • @param definition
    • @return
      */
      public String update(RouteDefinition definition) {
      try {
      log.info(“gateway update route {}”,definition);
      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) {
      return “update route fail”;
      }
      }

    /**

    • 增加路由
    • @param definition
    • @return
      */
      public String add(RouteDefinition definition) {
      log.info(“gateway add route {}”,definition);
      routeDefinitionWriter.save(Mono.just(definition)).subscribe();
      this.publisher.publishEvent(new RefreshRoutesEvent(this));
      return “success”;
      }
      }
      `
通过nacos下发动态路由配置,监听Nacos中gateway-route配置

`@Component
@Slf4j
@DependsOn({“gatewayConfig”}) // 依赖于gatewayConfig bean
public class DynamicRouteServiceImplByNacos {

@Autowired
private DynamicRouteServiceImpl dynamicRouteService;


private ConfigService configService;

@PostConstruct
public void init() {
    log.info("gateway route init...");
    try{
        configService = initConfigService();
        if(configService == null){
            log.warn("initConfigService fail");
            return;
        }
        String configInfo = configService.getConfig(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP, GatewayConfig.DEFAULT_TIMEOUT);
        log.info("获取网关当前配置:\r\n{}",configInfo);
        List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
        for(RouteDefinition definition : definitionList){
            log.info("update route : {}",definition.toString());
            dynamicRouteService.add(definition);
        }
    } catch (Exception e) {
        log.error("初始化网关路由时发生错误",e);
    }
    dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID,GatewayConfig.NACOS_ROUTE_GROUP);
}

/**
 * 监听Nacos下发的动态路由配置
 * @param dataId
 * @param group
 */
public void dynamicRouteByNacosListener (String dataId, String group){
    try {
        configService.addListener(dataId, group, new Listener()  {
            @Override
            public void receiveConfigInfo(String configInfo) {
                log.info("进行网关更新:\n\r{}",configInfo);
                List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
                for(RouteDefinition definition : definitionList){
                    log.info("update route : {}",definition.toString());
                    dynamicRouteService.update(definition);
                }
            }
            @Override
            public Executor getExecutor() {
                log.info("getExecutor\n\r");
                return null;
            }
        });
    } catch (NacosException e) {
        log.error("从nacos接收动态路由配置出错!!!",e);
    }
}

/**
 * 初始化网关路由 nacos config
 * @return
 */
private ConfigService initConfigService(){
    try{
        Properties properties = new Properties();
        properties.setProperty("serverAddr",GatewayConfig.NACOS_SERVER_ADDR);
        properties.setProperty("namespace",GatewayConfig.NACOS_NAMESPACE);
        return configService= NacosFactory.createConfigService(properties);
    } catch (Exception e) {
        log.error("初始化网关路由时发生错误",e);
        return null;
    }
}

}
`

配置文件路由

`@Configuration(“gatewayConfig”)
public class GatewayConfig {

public static final long DEFAULT_TIMEOUT = 30000;

public static String NACOS_SERVER_ADDR;

public static String NACOS_NAMESPACE;

public static String NACOS_ROUTE_DATA_ID;

public static String NACOS_ROUTE_GROUP;

@Value("${spring.cloud.nacos.discovery.server-addr}")
public void setNacosServerAddr(String nacosServerAddr){
    NACOS_SERVER_ADDR = nacosServerAddr;
}

@Value("${spring.cloud.nacos.discovery.namespace}")
public void setNacosNamespace(String nacosNamespace){
    NACOS_NAMESPACE = nacosNamespace;
}

@Value("${nacos.gateway.route.config.data-id}")
public void setNacosRouteDataId(String nacosRouteDataId){
    NACOS_ROUTE_DATA_ID = nacosRouteDataId;
}

@Value("${nacos.gateway.route.config.group}")
public void setNacosRouteGroup(String nacosRouteGroup){
    NACOS_ROUTE_GROUP = nacosRouteGroup;
}

}
`

nacos 配置详情

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xo47W8ib-1666658635332)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bb88787fe7db410d832b1db40bc13bdc~tplv-k3u1fbpfcp-watermark.image)]

至此我们实现动态路由就结束了,不足之处,欢迎交流指正
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要基于Nacos实现Spring Cloud Gateway的动态网关路由,可以按照以下步骤进行操作: 1. 添加依赖:在Spring Cloud Gateway项目的pom.xml文件中添加相应的依赖,包括spring-cloud-starter-gatewayspring-cloud-starter-alibaba-nacos-discovery等。 2. 配置Nacos注册中心:在application.properties或application.yml配置文件中添加Nacos注册中心的相关配置,包括Nacos服务器地址、命名空间、分组等信息。 3. 配置动态路由:创建一个RouteLocator Bean,并在其中使用Nacos的服务发现来定义动态路由规则。可以通过Nacos的配置中心来管理路由规则的动态更新。 ```java @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("service_route", r -> r.path("/api/v1/**") .uri("lb://service-provider")) .build(); } } ``` 上述示例中,定义了一个名为service_route的路由规则,将请求路径以/api/v1/开头的请求转发到名为service-provider的微服务上。 4. 启动Gateway应用:启动Spring Cloud Gateway应用,它会自动从Nacos注册中心获取动态路由规则并进行路由转发。 5. 管理动态路由:使用Nacos的配置中心来管理动态路由规则。可以通过Nacos的控制台或API来添加、修改或删除路由规则,Gateway应用会自动更新并生效。 通过以上步骤,就可以基于Nacos实现Spring Cloud Gateway的动态网关路由了。你可以根据实际需求和业务场景,添加更多的路由规则和配置。希望对你有所帮助!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值