gateway+nacos动态路由配置

gateway+nacos动态路由配置

spring cloud微服务场景下,需要使用到路由转发组。本文将从3个方面介绍路由配置:

  1. 简单的场景
  2. 通过nacos动态路由配置
  3. 常用配置属性

1. 准备工作和前置条件

我使用的版本:

spring-boot版本: 2.3.12.RELEASE
spring-cloud版本: Hoxton.SR12
nacos版本: 2.2.9.RELEASE

各组件版本尽量与这个一致,版本参考: https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

配置gateway路由前,需要先部署nacos、创建gateway项目、分别部署2个springboot服务(app1、app2)。这里略过,如果有人读我的文章、需要参考代码请留言,我抽空整理上传。

2. gateway简单的静态路由配置

在application.yml可以直接配置路由,下面是我的配置文件

server:
  port: 8000
spring:
  application:
    name: app-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.128.3:8848
        namespace: *****
# 简单场景使用本地配置
#      config:
#        server-addr: 192.168.128.3:8848
#        namespace: *****
    inetutils:
      preferred-networks: 192.168  # 首选IP
    gateway:
      httpclient:
        connect-timeout: 1000
      default-filters:
        - PreserveHostHeader #发送原主机头
      discovery:
        locator:
          enabled: true  # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
          lower-case-service-id: true #把服务名转换为小写
      routes:
        - id: app1
          uri: lb://app1    #lb代表负载均衡
          predicates:
            - Path=/app1/**
        - id: app2
          uri: lb://app2    #匹配后提供服务的路由地址,lb代表负载均衡
          predicates:
            - Path=/app2/**   #断言,路径相匹配的进行路由转发

3. 启动各个服务:nacos、app1、app2、gateway

先启动并登录nacos,进入服务列表页面,复制命名空间id
在这里插入图片描述

然后修改另外3个服务的配置文件的spring.cloud.nacos.discovery.server-addr、namespace属性,让各个服务能找到nacos。
gateway配置文件

spring:
  application:
    name: app-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.128.3:8848
        namespace: *****
    inetutils:
      preferred-networks: 192.168  # 首选IP

app1

server:
  servlet:
    context-path: /app1
spring:
  application:
    name: app1
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.128.3:8848
        namespace: *****
    inetutils:
      preferred-networks: 192.168  # 首选IP

app2

server:
  servlet:
    context-path: /app2
spring:
  application:
    name: app2
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.128.3:8848
        namespace: *****
    inetutils:
      preferred-networks: 192.168  # 首选IP

启动这3个服务。然后在nacos服务列表页面可以看到这3个服务。

浏览器访问gateway并加上app1或app2的路径,gateway会自动将/app1、/app2转发到对应的服务。

3. 动态路由配置

通过静态文件配置路由,当配置改变时要重启gateway才能更新配置,或者要开发更新配置的代码来更新。gateway提供了动态路由配置的方式来解决这个问题。

3.1 在nacos新建配置,最好和前面的命名空间相同

在这里插入图片描述

DataId: app-gateway-router, 配置格式:TEXT

[
    {
        "id": "app1-route",
        "uri": "lb://app1",
        "predicates": [
            {
                "name": "Path",
                "args": {
                    "pattern": "/app1/**"
                }
            }
        ]
    },
    {
        "id": "app2-route",
        "uri": "lb://app2",
        "predicates": [
            {
                "name": "Path",
                "args": {
                    "pattern": "/app2/**"
                }
            }
        ]
    }
]

3.2 在gateway增加读取动态配置的代码

DynamicGatewayRouteConfig


@Component
public class DynamicGatewayRouteConfig implements ApplicationEventPublisherAware {
    private String dataId = "app-gateway-router";
    private String group = "DEFAULT_GROUP";
    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;
    @Value("${spring.cloud.nacos.config.namespace}")
    private String namespace;
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    private static final List<String> ROUTE_LIST = new ArrayList<String>();

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

    @NacosInjected
    private ConfigService configService;

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

    @PostConstruct
    public void dynamicRouteByNacosListener() {
        try {
            if(StringUtils.isEmpty(group))
                group = "";
            configService = initConfigService();
            if(configService == null){
                logger.warn("initConfigService 失败!");
                return;
            }
            String configInfo = configService.getConfig(dataId, group, 3000);
            logger.info("获取网关当前配置:\r\n{}",configInfo);
            List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
            for(RouteDefinition definition : definitionList){
                logger.info("addRoute when startup : {}",definition.toString());
                addRoute(definition);
            }
        } catch (NacosException e) {
            logger.error("发生错误!", e);
        }
        dynamicRouteByNacosListener(dataId,group);
    }


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


    public String deleteRoute(String id) {
        try {
            logger.info("gateway delete route id {}",id);
            this.routeDefinitionWriter.delete(Mono.just(id));
            return "delete success";
        } catch (Exception e) {
            return "delete fail";
        }
    }

    private String updateRoute(RouteDefinition definition) {
        try {
            logger.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.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
            return "success";
        } catch (Exception e) {
            return "update route fail";
        }
    }

    private void clearRoute() {
        for (String id : ROUTE_LIST) {
            this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
        }
        ROUTE_LIST.clear();
    }

    private void addRoute(RouteDefinition definition) {
        logger.info("gateway add route {}",definition);
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
        } catch (Exception e) {
            logger.error("发生错误!", e);
        }
    }
}

3.3 修改gateway配置文件

增加nacos配置中心:

      config:
        server-addr: 192.168.128.3:8848
        namespace: *****

将配置文件里静态路由的配置删除或注释

3.4. 重启gateway

重启gateway,它会连接nacos并读取配置、注册路由。至此动态路由配置完成,

4. gateway里的常用配置

常用配置请看我的下一篇: 《Spring cloud Gateway常用配置》

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值