乐趣区

关于springcloud:Spring-cloud-gateway-nacos实现动态路由

Spring cloud gateway 的三个外围概念

route 路由

能够了解为一条转发规定,蕴含:

  • id
  • 指标 url
  • 断言(predicate)
  • 过滤器(filter)
    若断言为 true,则申请将经由 filter 被路由到指标 url。

predicate 断言

能够了解为一个条件判断,对以后的 http 申请进行指定规定的匹配,当匹配上规定时,断言才为 true,此时申请会被路由到指标地址,服务或者过滤器

filter 过滤器

对申请进行解决的逻辑局部。当申请的断言为 true 时,会被路由到设置好的过滤器,以对申请进行解决。例如,能够为申请增加一个申请头,或增加一个申请参数,或对申请 URI 进行批改等。

Nacos 作为路由规定的配置核心

nacos 的配置和运行如下

  • MySQL 配置运行
  • 运行 MySQL

    docker run -p 3306:3306 --name mysql \
    -v /Users/wangbin/dockerall/mysql/log:/var/log/mysql \
    -v /Users/wangbin/dockerall/mysql/data:/var/lib/mysql \
    -v /Users/wangbin/dockerall/mysql/conf:/etc/mysql \
    -e MYSQL_ROOT_PASSWORD=root \
    -d mysql:5.7
    
    docker exec -it mysql bash
    
    mysql -proot
    
    create database nacos_config;
    
    use nacos_config;
    
  • 执行 SQL
    SQL 内容
  • 新建 /xxxxx/nacos_docker/init.d/ 目录并生成 custom.properties 文件。文件内容如下

    management.endpoints.web.exposure.include=*
    server.contextPath=/nacos
    server.servlet.contextPath=/nacos
    server.port=8848
    spring.datasource.platform=mysql
    db.num=1
    db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
    db.user=root
    db.password=root
    nacos.cmdb.dumpTaskInterval=3600
    nacos.cmdb.eventTaskInterval=10
    nacos.cmdb.labelTaskInterval=300
    nacos.cmdb.loadDataAtStart=false
    management.metrics.export.elastic.enabled=false
    management.metrics.export.influx.enabled=false
    server.tomcat.accesslog.enabled=true
    server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i
    nacos.security.ignore.urls=/,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/v1/auth/login,/v1/console/health/**,/v1/cs/**,/v1/ns/**,/v1/cmdb/**,/actuator/**,/v1/console/server/**
    nacos.naming.distro.taskDispatchThreadCount=1
    nacos.naming.distro.taskDispatchPeriod=200
    nacos.naming.distro.batchSyncKeyCount=1000
    nacos.naming.distro.initDataRatio=0.9
    nacos.naming.distro.syncRetryDelay=5000
    nacos.naming.data.warmup=true
    nacos.naming.expireInstance=true
  • 新建 logs 目录
  • 运行 Nacos

    docker run
    --name nacos -d
    -p 8848:8848
    --privileged=true
    --restart=always
    -e JVM_XMS=256m
    -e JVM_XMX=256m
    -e MODE=standalone
    -e PREFER_HOST_MODE=hostname
    -v /xxxxx/nacos_docker/init.d/custom.properties:/home/nacos/init.d/custom.properties
    -v /xxxxx/nacos_docker/logs:/home/nacos/logs
    nacos/nacos-server
    
  • 拜访 http://localhost:8848
  • 输出 nacos/nacos 登陆

新建配置内容

内容如下

[{
    "id":"user-router",
    "predicates":[
      {
        "args":{"pattern": "/usr/**"},
        "name": "Path"
      }
    ],
    "filters": [
      {
        "name": "StripPrefix",
        "args": {"parts": "1"}
      }
    ],
    "uri": "lb://user-service"
}]

对应的 yml 内容如 route 局部

spring:
  application:
    name: dynamicgateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置 Nacos 地址
      config:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: user-router
          uri: lb://user-service
          predicates:
            - Path=/usr/**
      filters:
        - StripPrefix=1 # 示意在转发时去掉 usr

新建我的项目
因为应用了 Spring cloud,Spring Cloud Alibaba,Nacos 之间的版本依赖关系如下
版本依赖关系

新建 DynamicGatewayRouteConfig

@Component
public class DynamicGatewayRouteConfig implements ApplicationEventPublisherAware {

    private String dataId = "gateway-router";

    private String group = "DEFAULT_GROUP";

    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

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

    @PostConstruct
    public void dynamicRouteByNacosListener() {
        try {ConfigService configService = NacosFactory.createConfigService(serverAddr);
            configService.getConfig(dataId, group, 5000);
            configService.addListener(dataId, group, new Listener() {public void receiveConfigInfo(String configInfo) {clearRoute();
                    try {List<RouteDefinition> gatewayRouteDefinitions = JSONObject.parseArray(configInfo, RouteDefinition.class);
                        for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {addRoute(routeDefinition);
                        }
                        publish();} catch (Exception e) {e.printStackTrace();
                    }
                }

                public Executor getExecutor() {return null;}
            });
        } catch (NacosException e) {e.printStackTrace();
        }
    }

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

    private void addRoute(RouteDefinition definition) {
        try {routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            ROUTE_LIST.add(definition.getId());
        } catch (Exception e) {e.printStackTrace();
        }
    }

    private void publish() {this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
    }

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

在 nacos 的 route 内容发生变化时会主动调用更新

bootstrap.yml 内容如下

spring:
  application:
    name: dynamicgateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置 Nacos 地址
 config:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
management:
  endpoints:
    web:
      exposure:
        include: '*'
 endpoint:
    health:
      show-details: always

具体代码
代码

退出移动版