Spring Cloud Alibaba | Nacos动态网关路由
Spring Cloud Alibaba | Gateway基于Nacos动态网关路由
本篇实战所使用Spring有关版本:
SpringBoot:2.1.7.RELEASE
Spring Cloud:Greenwich.SR2
Spring CLoud Alibaba:2.1.0.RELEASE
前面几篇文章我们介绍了《Nacos服务注册与发现》和《Nacos配置管理》,还没看过的小伙伴们快去看一下,本篇文章是建立在这两篇文章基础上的一次实战。
背景介绍
在Spring Cloud微服务体系下,常用的服务网关有Netflix公司开源的Zuul,还有Spring Cloud团队自己开源的Spring Cloud Gateway,其中NetFlix公司开源的Zuul版本已经迭代至2.x,但是Spring Cloud并未集成,目前Spring Cloud集成的Spring Cloud Zuul还是Zuul1.x,这一版的Zuul是基于Servlet构建的,采用的方案是阻塞式的多线程方案,即一个线程处理一次连接请求,这种方式在内部延迟严重、设备故障较多情况下会引起存活的连接增多和线程增加的情况发生。Spring Cloud自己开源的Spring Cloud Gateway则是基于Spring Webflux来构建的,Spring Webflux有一个全新的非堵塞的函数式 Reactive Web 框架,可以用来构建异步的、非堵塞的、事件驱动的服务,在伸缩性方面表现非常好。使用非阻塞API, Websockets得到支持,并且由于它与Spring紧密集成,将会得到更好的开发体验。
本文将基于Gateway服务网关来介绍如何使用Nacos的配置功能来实现服务网关动态路由。
实现方案
在开始之前我们先介绍一下具体实现方式:
- 路由信息不再配置在配置文件中,将路由信息配置在Nacos的配置中。
- 在服务网关Spring Cloud Gateway中开启监听,监听Nacos配置文件的修改。
- Nacos配置文件一旦发生改变,则Spring Cloud Gateway重新刷新自己的路由信息。
环境准备
首先,需要准备一个Nacos服务,我这里的版本是使用的Nacos v1.1.3,如果不会配置Nacos服务的同学,请参考之前的文章《Nacos服务中心初探》
工程实战
创建工程gateway-nacos-config,工程依赖pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springcloud.alibaba</groupId>
<artifactId>gateway-nacos-config</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-nacos-config</name>
<description>gateway-nacos-config</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<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-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</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>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 在使用Spring Cloud Alibaba组件的时候,在
<dependencyManagement>中需配置spring-cloud-alibaba-dependencies,它管理了Spring Cloud Alibaba组件的版本依赖。
配置文件application.yml如下:
server:
port: 8080
spring:
application:
name: spring-cloud-gateway-server
cloud:
nacos:
discovery:
server-addr: 192.168.44.129:8848
management:
endpoints:
web:
exposure:
include: '*'
spring.cloud.nacos.discovery.server-addr:配置为Nacos服务地址,格式为ip:port
接下来进入核心部分,配置Spring Cloud Gateway动态路由,这里需要实现一个Spring提供的事件推送接口ApplicationEventPublisherAware,代码如下:
@Component
public class DynamicRoutingConfig implements ApplicationEventPublisherAware {
private final Logger logger = LoggerFactory.getLogger(DynamicRoutingConfig.class);
private static final String DATA_ID = "zuul-refresh-dev.json";
private static final String Group = "DEFAULT_GROUP";
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher applicationEventPublisher;
@Bean
public void refreshRouting() throws NacosException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, "192.168.44.129:8848");
properties.put(PropertyKeyConst.NAMESPACE, "8282c713-da90-486a-8438-2a5a212ef44f");
ConfigService configService = NacosFactory.createConfigService(properties);
configService.addListener(DATA_ID, Group, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
logger.info(configInfo);
boolean refreshGatewayRoute = JSONObject.parseObject(configInfo).getBoolean("refreshGatewayRoute");
if (refreshGatewayRoute) {
List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(configInfo).getString("routeList")).toJavaList(RouteEntity.class);
for (RouteEntity route : list) {
update(assembleRouteDefinition(route));
}
} else {
logger.info("路由未发生变更");
}
}
});
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* 路由更新
* @param routeDefinition
* @return
*/
public void update(RouteDefinition routeDefinition){
try {
this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
logger.info("路由更新成功");
}catch (Exception e){
logger.error(e.getMessage(), e);
}
try {
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
logger.info("路由更新成功");
}catch (Exception e){
logger.error(e.getMessage(), e);
}
}
public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
RouteDefinition definition = new RouteDefinition();
// ID
definition.setId(routeEntity.getId());
// Predicates
List<PredicateDefinition> pdList = new ArrayList<>();
for (PredicateEntity predicateEntity: routeEntity.getPredicates()) {
PredicateDefinition predicateDefinition = new PredicateDefinition();
predicateDefinition.setArgs(predicateEntity.getArgs());
predicateDefinition.setName(predicateEntity.getName());
pdList.add(predicateDefinition);
}
definition.setPredicates(pdList);
// Filters
List<FilterDefinition> fdList = new ArrayList<>();
for (FilterEntity filterEntity: routeEntity.getFilters()) {
FilterDefinition filterDefinition = new FilterDefinition();
filterDefinition.setArgs(filterEntity.getArgs());
filterDefinition.setName(filterEntity.getName());
fdList.add(filterDefinition);
}
definition.setFilters(fdList);
// URI
URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
definition.setUri(uri);
return definition;
}
}
这里主要介绍一下refreshRouting()这个方法,这个方法主要负责监听Nacos的配置变化,这里先使用参数构建一个ConfigService,再使用ConfigService开启一个监听,并且在监听的方法中刷新路由信息。
Nacos配置如图:

{
"refreshGatewayRoute":false,
"routeList":[
{
"id":"github_route",
"predicates":[
{
"name":"Path",
"args":{
"_genkey_0":"/meteor1993"
}
}
],
"filters":[
],
"uri":"https://github.com",
"order":0
}
]
}
配置格式选择JSON,Data ID和Group与程序中的配置保持一致,注意,我这里的程序配置了namespace,如果使用默认namespace,可以不用配置。
这里配置了一个路由/meteor1993,直接访问这个路由会访问到作者的Github仓库。
剩余部分的代码这里就不一一展示了,已经上传至代码仓库,有需要的同学可以自行取用。
测试
启动工程,这时是没有任何路由信息的,打开浏览器访问:http://localhost:8080/meteor1993 ,页面返回404报错信息,如图:
同时,也可以访问链接:http://localhost:8080/actuator/gateway/routes ,可以看到如下打印:
[]
打开在Nacos Server端的UI界面,选择监听查询,选择namespace为springclouddev的栏目,输入DATA_ID为zuul-refresh-dev.json和Group为DEFAULT_GROUP,点击查询,可以看到我们启动的工程gateway-nacos-config正在监听Nacos Server端,如图:

笔者这里的本地ip为:192.168.44.1。监听正常,这时,我们修改刚才创建的配置,将里面的refreshGatewayRoute修改为true,如下:
{"refreshGatewayRoute": true, "routeList":[{"id":"github_route","predicates":[{"name":"Path","args":{"_genkey_0":"/meteor1993"}}],"filters":[],"uri":"https://github.com","order":0}]}
点击发布,可以看到工程gateway-nacos-config的控制台打印日志如下:
2019-09-02 22:09:49.254 INFO 8056 --- [38-2a5a212ef44f] c.s.a.g.config.DynamicRoutingConfig : {
"refreshGatewayRoute":true,
"routeList":[
{
"id":"github_route",
"predicates":[
{
"name":"Path",
"args":{
"_genkey_0":"/meteor1993"
}
}
],
"filters":[
],
"uri":"https://github.com",
"order":0
}
]
}
2019-09-02 22:09:49.268 INFO 8056 --- [38-2a5a212ef44f] c.s.a.g.config.DynamicRoutingConfig : 路由更新成功
这时,我们的工程gateway-nacos-config的路由已经更新成功,访问路径:http://localhost:8080/actuator/gateway/routes ,可以看到如下打印:
[{"route_id":"github_route","route_definition":{"id":"github_route","predicates":[{"name":"Path","args":{"_genkey_0":"/meteor1993"}}],"filters":[],"uri":"https://github.com","order":0},"order":0}]
我们再次在浏览器中访问链接:http://localhost:8080/meteor1993 ,可以看到页面正常路由到Github仓库,如图:

总结
至此,Nacos动态网关路由就介绍完了,主要运用了服务网关端监听Nacos配置改变的功能,实现服务网关路由配置动态刷新,同理,我们也可以使用服务网关Zuul来实现基于Nacos的动态路由功能。
基于这个思路,我们可以使用配置中心来实现网关的动态路由,而不是使用服务网关本身自带的配置文件,这样每次路由信息变更,无需修改配置文件而后重启服务。
目前市面上使用比较多的配置中心有携程开源的Apollo,服务网关还有Spring Cloud Zuul,下一篇文章我们介绍如何使用Apollo来实现Spring Cloud Zuul的动态路由。
示例代码
Spring Cloud Alibaba | Nacos动态网关路由的更多相关文章
- 0.9.0.RELEASE版本的spring cloud alibaba nacos+gateway网关实例
gateway就是用来替换zuul的,功能都差不多,我们看下它怎么来跟nacos一起玩.老套路,三板斧: 1.pom: <?xml version="1.0" encodin ...
- 0.9.0.RELEASE版本的spring cloud alibaba sentinel+gateway网关实例
sentinel除了让服务提供方.消费方用之外,网关也能用它来限流.我们基于上次整的网关(参见0.9.0.RELEASE版本的spring cloud alibaba nacos+gateway网关实 ...
- Spring Cloud Alibaba | Nacos服务中心初探
目录 Spring Cloud Alibaba | Nacos服务中心初探 1. 什么是Nacos? 1.1 Nacos 1.0 1.2 Nacos 2.0 2. Nacos 架构及概念 2.1 服务 ...
- Spring Cloud Alibaba | Nacos服务注册与发现
目录 Spring Cloud Alibaba | Nacos服务注册与发现 1. 服务提供者 1.1 pom.xml项目依赖 1.2 配置文件application.yml 1.3 启动类Produ ...
- Spring Cloud Alibaba | Nacos配置管理
目录 Spring Cloud Alibaba | Nacos配置管理 1. pom.xml 项目依赖 2. 在 bootstrap.properties 中配置 Nacos server 的地址和应 ...
- Spring Cloud Alibaba Nacos
1. Spring Cloud Alibaba 介绍 Spring Cloud Alibaba 为分布式应用程序开发提供了一站式解决方案.它包含了开发分布式应用程序所需的所有组件,使得你可以轻松地使用 ...
- Spring Cloud Alibaba Nacos Config 的使用
Spring Cloud Alibaba Nacos Config 的使用 一.需求 二.实现功能 1.加载 product-provider-dev.yaml 配置文件 2.实现配置的自动刷新 3. ...
- Spring Cloud Alibaba Nacos 服务注册与发现功能实现!
Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提供了两个重要的功能:服务注册与发现和统一的配置中心功能. 服务注册与发现功能解决了微服务集群中,调用者和服务提供者连 ...
- Spring Cloud Alibaba | Nacos集群部署
目录 Spring Cloud Alibaba | Nacos集群部署 1. Nacos支持三种部署模式 2. 集群模式下部署Nacos 2.1 架构图 2.2 下载源码或者安装包 2.3 配置集群配 ...
随机推荐
- spark 源码分析之十九 -- Stage的提交
引言 上篇 spark 源码分析之十九 -- DAG的生成和Stage的划分 中,主要介绍了下图中的前两个阶段DAG的构建和Stage的划分. 本篇文章主要剖析,Stage是如何提交的. rdd的依赖 ...
- Jmeter CSV config使用
1.添加线程组,自己给线程组命名 2.添加CSV data set config 如上,filename是文件的名字 新增.txt文件,将变量写在文件中,完成后,更名为.csv:变量之间用逗号隔开(第 ...
- unc路径
1.什么是UNC路径?UNC路径就是类似\\softer这样的形式的网络路径.UNC为网络(主要指局域网)上资源的完整 Windows 2000 名称.格式: \\servername\sharena ...
- Linux下安装配置Jmeter5.1,并执行jmx文件
Windows下的jmeter是GUI模式,可查看操作,但是GUI对性能的干扰比较大,所有一般压测会在Linux上运行. 下面是Linux下安装配置Jmeter5.1,并执行jmx文件的步骤, 一.安 ...
- 入门MySQL——架构篇
前言: 上篇文章我们介绍了入门MySQL的基本概念,看完上篇文章,相信你应该了解MySQL的前世今生了吧.本篇文章将带你从架构体系来学习MySQL.我认为学习MySQL架构体系应该是入门阶段必须的, ...
- 角度转弧度&根据弧度计算圆周上点的坐标的方法
角度转弧度: #define AngleToRadian(angle) (M_PI/180.0f)*angle 以正东面为0度起点计算指定角度所对应的圆周上的点的坐标: float radian = ...
- Scala的常用小技巧
1."RichString.java".stripSuffix(".java") == "RichString" "http:// ...
- ubuntu清理系统垃圾与备份
虽然linux下不会有windows下的那么多垃圾和磁盘碎片!但还是会留下一些用不着的临时文件或是多次升级后的N个旧的内核! 1,非常有用的清理命令: sudo apt-get autoclean s ...
- <<Modern CMake>> 翻译 2.4 项目目录结构
<<Modern CMake>> 翻译 2.4 项目目录结构 本节内容有点跑题.但我认为这是一个很好的方法. 我将告诉你如何规划项目的目录. 这是基于惯例,但将帮助您: 轻松阅 ...
- Python 与数据库交互
安装:pip3 install pymysql 引入模块在python3里:from pymysql import * 使用步骤:1.创建Connection对象,用于建立与数据库的连接,创建对象调用 ...