阅读 790

Spring Gateway 集成Nacos 实现动态路由配置(动态路由的配置)

通过Spring Gateway 集成Nacos实现配置管理,并且实现动态路由管理。

一、创建test-gateway项目,POM文件如下:

	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.golte.parent</groupId>
		<artifactId>golte-parent</artifactId>
		<version>1.0.0</version>
	</parent>
	<groupId>com.golte.gateway</groupId>
	<artifactId>golte-gateway</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>golte-gateway</name>
	<description>Gateway project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring.cloud.version>Hoxton.SR8</spring.cloud.version>
    <alibaba.cloud.version>2.2.3.RELEASE</alibaba.cloud.version>
    <fastjson.version>1.2.73</fastjson.version>
	</properties>

	<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-config</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
		</dependency>
		<!-- sentinel提供的gataway适配器 -->
		<dependency>
			<groupId>com.alibaba.cloud</groupId>
			<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
		</dependency>
		<!-- 对外暴露 Spring Boot 监控指标 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>${fastjson.version}</version>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring.cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>com.alibaba.cloud</groupId>
				<artifactId>spring-cloud-alibaba-dependencies</artifactId>
				<version>${alibaba.cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<build>
		<finalName>test-gateway</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build></project>

二、创建项目配置文件bootstrap.yml

server:
    port: 80spring:
    profiles:
       active: dev
    application: 
       name: test-gateway
    cloud:
       nacos: 
         config:
            namespace: ${spring.profiles.active}
            server-addr: http://127.0.0.1:8848
            extension-configs[0]: 
                    data-id: test_gateway_commons.yml
                    group: DEFAULT_GROUP
                    refresh: true#Nacos动态路由配置,json格式nacos: 
    gateway: 
         route: 
            config: 
               data-id: gateway_dynamic_router
               group: DEFAULT_GROUP

a、test_gateway_commons.yml内容如下:

#sentinel 相关配置spring: 
    cloud: 
       sentinel: 
           transport: 
                dashboard: http://127.0.0.1:8080
                port: 8719
           scg: 
                fallback: 
                   mode: response
                   response-status: 455
                   response-body: error!
       nacos: 
          discovery: 
              namespace: dev
              server-addr: 127.0.0.1:8848management: 
      endpoints: 
            web: 
              exposure: 
                  include: '*'

三、创建网关配置类 GatewayConfig.java

import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Configuration;@Configurationpublic 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;
      }
}

四、创建动态路由服务
DynamicRouteServiceImpl.java

import org.springframework.beans.factory.annotation.Autowired;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.Service;import lombok.extern.slf4j.Slf4j;import reactor.core.publisher.Mono;/**
 * 动态更新路由网关service
 * 1)实现一个Spring提供的事宜推送接口ApplicationEventPublisherAware
 * 2)提供动态路由的基础方式,可通过获取bean操作该类的方式。该类提供新增路由、更新路由、删除路由,然后实现公布的功效。
 */@Slf4j@Servicepublic 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读取动态路由配置服务
DynamicRouteServiceImplByNacos.java

import java.util.List;import java.util.Properties;import java.util.concurrent.Executor;import javax.annotation.PostConstruct;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.gateway.route.RouteDefinition;import org.springframework.context.annotation.DependsOn;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 lombok.extern.slf4j.Slf4j;/**
 *
 * 通过nacos下发动态路由设置,监听Nacos中gateway-route设置
 *
 */@Component@Slf4j@DependsOn({ "gatewayConfig" }) // 依赖于gatewayConfig beanpublic 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;
        }
      }
}

六、配置动态路由配置文件gateway_dynamic_router,内容如下:

[{    "id": "user-admin-router",    "order": 5,    "predicates": [{        "args": {            "pattern": "/useradmin/**"
        },        "name": "Path"
    }],    "filters":[
      {          "name":"StripPrefix",          "args":{"_genkey_0":1}
      }
    ],    "uri": "lb://test-user-admin"},{    "id": "user-app-router",    "order": 4,    "predicates": [{        "args": {            "pattern": "/users/**"
        },        "name": "Path"
    }],    "filters":[
      {          "name":"StripPrefix",          "args":{"_genkey_0":1}
      }
    ],    "uri": "lb://test-user-app"}]

通过以上步骤就完成Spring Gateway 集成Nacos 实现动态路由配置功能。以后只要通过修改Nacos的配置文件就可以时间服务的动态上下线了。不需要再重启网关了。


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐