Spring Cloud Gateway 整合 Nacos 实现服务请求自动转发+负载均衡!
一、背景介绍
在之前的文章中,我们介绍了 Spring Cloud Gateway 的基础用法。本文将继续研究 Gateway 的更高级用法,比如整合服务注册中心实现请求自动路由转发、整合服务配置中心实现路由规则动态加载等。
下面我们一起来看看相关的实现思路。
二、整合注册中心
在上篇文章中,我们介绍了在 Spring Cloud Gateway 中通过配置的方式就可实现将请求转发到某个目标服务上。而在微服务架构中,服务中心往往注册了很多服务,如果每个服务都进行单独配置的话,那这份工作无疑既劳累又枯燥。
实际上,Spring Cloud Gateway 提供了一种默认转发的能力,只要将 Spring Cloud Gateway 注册到服务中心,Spring Cloud Gateway 默认就会自动代理服务中心的所有服务,并以服务名作为目标 URI 来自动创建动态路由。
整个服务体系的工作流程就会变成如下图。

下面我们以 Nacos 作为服务注册为例,通过具体的案例看看如何使用 Spring Cloud Gateway 来实现将服务请求进行转发的效果。
在构建服务网关之前,需要先部署并启动 Nacos,这一步比较简单,在此就不重复介绍了。如果还不会的小伙伴,可以参考之前写过的 Nacos 作为服务注册中心的技术文章。
2.1、构建服务网关
使用 Spring Cloud Gateway 来构建服务网关也非常简单,之前我们已经详细介绍过,将之前创建的gateway-server
复制一个新服务网关工程,命名为gateway-nacos
,并在pom.xml
中引入 Nacos 注册中心依赖包,示例如下:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencies>
<!-- 引入 Spring Cloud Gateway 网关组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos 作为注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- 引入 springBoot 版本号 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 引入 spring cloud 版本号 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 引入 spring cloud alibaba 适配的版本号 -->
<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>
2.2、修改配置文件
修改application.yaml
配置文件,增加 Nacos 注册中心相关的配置项。
完整配置如下:
server:
port: 8080
spring:
application:
name: gateway-nacos
cloud:
# Spring Cloud Gateway 配置项,对应 GatewayProperties 类
gateway:
# 与 Spring Cloud 注册中心的集成,对应 DiscoveryLocatorProperties 类
discovery:
locator:
enabled: true # 是否开启,默认为 false 关闭
url-expression: "'lb://' + serviceId" # 路由的目标地址的表达式,默认为"'lb://' + serviceId"
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
关键参数作用解读:
nacos.discovery.server-addr
:顾名思义,使用 Nacos 作为 Spring Cloud 的服务注册中心gateway.discovery.locator.enabled
:是否开启与 Spring Cloud 注册中心的集成功能,默认false
,这里需要开启gateway.discovery.locator.url-expression
:路由的目标地址的 Spring EL 表达式,默认为"'lb://' + serviceId"
可能大家对url-expression
这个配置项不太理解,我们来举个例子。
假设注册中心有user-service
和order-service
两个服务,url-expression
这个配置项最终效果和如下配置等价:
spring:
cloud:
gateway:
routes:
- id: ReactiveCompositeDiscoveryClient_user-service
uri: lb://user-service
predicates:
- Path=/user-service/**
filters:
- RewritePath=/user-service/(?<remaining>.*), /${remaining}
- id: ReactiveCompositeDiscoveryClient_order-service
uri: lb://order-service
predicates:
- Path=/order-service/**
filters:
- RewritePath=/order-service/(?<remaining>.*), /${remaining}
其中uri: lb://user-service
表达式是user-service
服务实例地址的一种简写,lb://
前缀表示将请求以负载均衡方式转发到对应的目标服务实例上。
2.3、构建业务微服务
为了方便测试服务的路由效果,我们还需要创建一个 Spring Boot 服务,并将服务注册到 Nacos,实现方式也很简单,只需如下几步即可完成。
首先,创建一个 SpringBoot 工程,命名为user-service
,其pom.xml
与上文类似,修改dependencies
内容,改成如下内容即可。
<dependencies>
<!-- SpringBoot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
然后,创建一个服务启动类并添加@EnableDiscoveryClient
,将当前服务注册到 Nacos。
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
接着,创建一个 web 接口,以便测试服务的转发效果,示例如下:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello,我是用户服务";
}
}
最后,创建application.properties
配置文件中添加服务注册中心地址,示例如下:
spring.application.name=user-service
server.port=9010
# 设置Nacos的服务地址,多个地址可使用【,】分隔
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
2.4、服务测试
将服务网关和user-service
都启动起来,访问 Nacos 服务控制台,可以看到服务的注册信息。

Spring Cloud Gateway 注册到服务中心之后,网关会自动代理所有注册中心的服务,访问这些服务的方式为:
http://网关地址:端口/服务中心注册 serviceId/具体服务接口的url
比如,访问http://127.0.0.1:8080/user-service/hello
,它会自动转发到user-service
服务的/hello
接口上,返回结果如下图。

当一个服务在多个机器上部署时,服务网关会依次轮流请求,实现负载均衡的效果。
三、整合配置中心
在上文中,Spring Cloud Gateway 整合服务注册中心之后,会自动代理所有注册中心的服务。
但是很多时候,我们并不想通过网关把服务都暴露出去,每个服务的路由规则可能不同,会存在配置不同过滤器的情况,并且可能需要经常经常调整,这个时候如何处理呢?
此时可以借助服务配置中心,将路由规则从服务网关中抽离出来,通过配置中心实现服务网关动态加载路由规则。
Spring Cloud 支持的配置中心组件有很多,比如 Config、Apollo、Nacos 等。其中 Nacos 应用比较广泛,因为它既可以做服务注册中心又可以做服务配置中心。
下面我们还是以 Nacos 作为服务配置中心为例,通过具体的案例看看如何使用 Spring Cloud Gateway 来实现将路由规则动态加载效果。
3.1、构建服务网关
还是以上文的gateway-nacos
服务网关工程为例,复制一个新的服务网关工程,命名为gateway-application
,并在pom.xml
中引入 Nacos 配置中心依赖包,示例如下:
<dependencies>
<!-- 引入 Spring Cloud Gateway 网关组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos 作为注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Nacos 作为配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
3.2、修改配置文件
因为Nacos
配置中心的配置项,只有在bootstrap.yaml
才能生效。
将application.yaml
文件修改成bootstrap.yaml
文件,并添加Nacos
配置中心相关的配置项。
配置内容如下:
server:
port: 8080
spring:
application:
name: gateway-application
cloud:
nacos:
# Nacos 作为注册中心
discovery:
server-addr: 127.0.0.1:8848
# Nacos 作为配置中心,对应 NacosConfigProperties 配置属性类
config:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
namespace: # 对应 Nacos 的命名空间,默认为 null
group: DEFAULT_GROUP # 对应 Nacos 配置分组,默认为 DEFAULT_GROUP
name: gateway-config # 对应 Nacos 配置集的 dataId,默认为 spring.application.name
file-extension: yaml
在上文中,我们配置了一个dataId
为gateway-config
,所属分组为DEFAULT_GROUP
的配置文件。
接着,在 nacos 配置中心创建对应的配置项并发布,示例如下:

配置内容为:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/user-service/**
filters:
- RewritePath=/user-service/(?<remaining>.*), /${remaining}
当网关启动时会自动将 Nacos 中配置中心中的路由规则内容载入到服务容器中,并自动进行刷新。
3.3、服务测试
最后将网关服务启动,再次访问http://127.0.0.1:8080/user-service/hello
,会自动转发到user-service
服务的/hello
接口上。

回到 Nacos 配置中心页面修改路由规则,将/user-service
路径改成/user
。

然后访问http://127.0.0.1:8080/user/hello
,返回结果如下图。

可以清晰的看到,服务网关中的路由规则也被动态刷新了。
四、小结
最后总结一下,Spring Cloud Gateway 是一个功能非常强大的服务网关,在微服务架构中通常与服务注册中心和配置中心搭配使用,以此完成服务接口的统一请求转发效果。
五、参考
1.https://www.iocoder.cn/Spring-Cloud/Spring-Cloud-Gateway/?self
作者:潘志的技术笔记
出处:https://pzblog.cn/
版权归作者所有,转载请注明出处
