Spring Cloud Gateway③编码实现动态增加、修改、删除路由

背景

以上文章演示了Gateway的部分功能的自定义开发,我们在实际业务中,很多转发的路由并不是通过配置文件提前配置好的,可能是通过配置中心获取并且会动态变化,新开发好的API需要挂到API网关上,希望通过仅修改配置解决,API网关不需要重启,那么我们就需要基于Gateway动态增加、修改、删除路由的能力。

本文开发环境介绍

开发依赖版本
Spring Boot2.7.0
Spring Cloud2021.0.1
Spring Cloud Alibaba2021.0.1.0

本文继续接着上一篇文章往下讲,代码和配置都是接着上一篇,如有看不懂的地方可以把前面关于Gateway的内容过目一下。

新增路由

实现ApplicationEventPublisherAware接口

import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.SneakyThrows;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.ArrayList;

@RequiredArgsConstructor
@Configuration
public class RouteAutoConfiguration implements ApplicationEventPublisherAware {

    private final RouteDefinitionWriter routeDefinitionWriter;
    private final RouteLocator routeLocator;
    @Setter
    private ApplicationEventPublisher applicationEventPublisher;

    @SneakyThrows
    @PostConstruct
    public void init() {
        RouteDefinition routeDefinition = new RouteDefinition();
        routeDefinition.setId("manual-route-1");
        routeDefinition.setUri(new URI("https://news.baidu.com/"));
        routeDefinition.setPredicates(new ArrayList<PredicateDefinition>() {{
            add(new PredicateDefinition("Path=/baidu/news/**"));
        }});
        routeDefinition.setFilters(new ArrayList<FilterDefinition>() {{
            add(new FilterDefinition("StripPrefix=2"));
        }});
        routeDefinition.setOrder(-1);
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }
}

代码新增了一条新的路由转发规则,把/baidu/news/转发到https://news.baidu.com/

验证新路由

在浏览器输入http://localhost:8081/baidu/news
在这里插入图片描述
出现以上图片内容,表示成功转发。

注意

在配置文件中有一个/baidu的转发,新增的/baidu/news//baidu子路径,Gateway会根据顺序进行匹配,先匹配到哪条符合条件的规则就会执行哪个规则,所以新增路由的代码中有一句routeDefinition.setOrder(-1);,这个顺序放在了配置文件中/baidu的前面。

修改路由

在第①篇文章中,演示了Demo过滤器的配置,那么我们现在尝试通过编码的方式动态修改已经配置好的路由规则,把/baidu/Demo过滤器的第3个参数进行修改

源码解析

  • yml文件中配置的路由规则会映射到GatewayProperties这个类中
  • 根据GatewayProperties类会生成PropertiesRouteDefinitionLocator这个Bean
  • 具体的Bean构造可以查看GatewayAutoConfiguration这个类的源码
	@Bean
	@ConditionalOnMissingBean
	public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
		return new PropertiesRouteDefinitionLocator(properties);
	}

看到上面这段代码,我们就可以生成我们自己的PropertiesRouteDefinitionLocator

构建类型为PropertiesRouteDefinitionLocator的Bean

import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Optional;

@Configuration
public class RouteDefinitionLocatorAutoConfiguration {

    @Bean
    public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
        Optional<RouteDefinition> optional = properties.getRoutes().stream().filter(r->r.getId().equals("baidu")).findAny();
        if(optional.isPresent()) {
            Optional<FilterDefinition> filterOptional = optional.get().getFilters().stream().filter(f->f.getName().equals("Demo")).findAny();
            filterOptional.get().getArgs().put(NameUtils.generateName(2), "manual");
        }
        return new PropertiesRouteDefinitionLocator(properties);
    }
}

上面的代码把配置文件中的world2修改成了manual

验证修改后的路由

  • 在浏览器输入http://localhost:8081/baidu
  • 在控制台可以看到如下输出
    在这里插入图片描述

删除路由

重新修改上面的RouteDefinitionLocatorAutoConfiguration类

@Configuration
public class RouteDefinitionLocatorAutoConfiguration {

    @Bean
    public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
        Optional<RouteDefinition> optional = properties.getRoutes().stream().filter(r->r.getId().equals("baidu")).findAny();
        if(optional.isPresent()) {
            Optional<FilterDefinition> filterOptional = optional.get().getFilters().stream().filter(f->f.getName().equals("Demo")).findAny();
            filterOptional.get().getArgs().put(NameUtils.generateName(2), "manual");
        }

        Optional<RouteDefinition> optional2 = properties.getRoutes().stream().filter(r->r.getId().equals("demoSwagger")).findAny();
        if(optional2.isPresent()) {
            properties.getRoutes().remove(optional2.get());
        }

        return new PropertiesRouteDefinitionLocator(properties);
    }
}

代码中把demoSwagger这个路由删除了

验证删除后的效果

在浏览器再次输入http://localhost:8081/swagger-ui/index.html
在这里插入图片描述

总结

以上示例通过代码的方式对路由进行了动态新增、修改和删除,有了这些动态的操作,基本上可以满足我们很多实际的业务场景了,比如在配置中心修改路由规则后,可以使用RouteDefinitionWriter动态刷新路由,勿需重启Gateway服务;也可以通过构造PropertiesRouteDefinitionLocator方式,结合实际业务规则,修改静态配置的路由。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Nacos是一个分布式的服务注册和发现系统。Spring Cloud Gateway是开源的网关,可以实现动态路由。结合Nacos和Spring Cloud Gateway可以实现动态路由的功能。 下面是通过Nacos实现Spring Cloud Gateway动态路由的步骤: 1. 添加Nacos组件。在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> ``` 2. 实现Spring Cloud Gateway注册到Nacos的功能。 在application.yml文件中添加以下配置: ``` spring: application: name: gateway-service cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true ``` 其中,将enabled设置为true,表示启用Spring Cloud Gateway的服务发现功能;将lower-case-service-id设置为true,表示服务名全部转换为小写。 3. 实现动态路由。 在Nacos中创建config和route两个配置。config配置用来存放动态路由信息,route配置用来存放每个服务的路由信息。 在route配置中添加以下配置: ``` spring: cloud: gateway: routes: - id: user-service uri: loadbalancer://user-service predicates: - Path=/users ``` 其中,id表示服务名,uri表示服务的负载均衡地址,predicates表示路由谓语,可以是Path、Query等。 在config配置中添加以下配置: ``` spring: cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true routes: - id: user-service predicates: - Path=/api/users/** filters: - StripPrefix=1 uri: lb://user-service metadata: version: 1.0 ``` 其中,id表示服务名,predicates表示路由谓语,filters表示过滤器,StripPrefix表示去掉前缀的过滤器,uri表示服务的负载均衡地址,metadata表示元数据信息。 通过以上配置,就可以实现Nacos和Spring Cloud Gateway动态路由的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

太空眼睛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值