在之前的篇章中,我们访问账户服务、商品服务、订单服务时,都要分别指定服务对应的端口进行访问。在实际应用中,服务的实际端口是不对外暴露的。如果要搭建更多的服务,那么我们对服务的访问将要维护更多的端口和访问路径。对此,本篇将介绍使用 Spring Cloud Gateway 对服务入口进行统一管理。
1. 关于 Spring Cloud Gateway
Spring Cloud Gateway 是 Spring Cloud 生态系统中的一个项目,旨在提供一种简单而有效的方式来路由到 api,并为它们提供横切关注点,例如:安全性、监控/指标和弹性。关于 Spring Cloud Gateway 的详细使用,可以参考官方文档(链接地址)。
2. 版本选择
由于我们 Spring Cloud Alibaba 选择的是 2022.0.0.0 版本,其中的 Spring Cloud 版本为 2022.0.0。该版本的 Spring Cloud 中的 Spring Cloud Gateway 版本为 4.0.0,因此,我们的 Spring Cloud Gateway 也选择版本为 4.0.0。
3. 项目搭建
由于 Spring Cloud Gateway 不承担过多的业务处理,其主要职责还是路由管理。因此对于 Spring Cloud Gateway 工程架构,我们采用基于 Spring Boot 的 MVC 架构即可。
在 mall-demo 工程下创建 Spring Cloud Gateway 子工程,名称为:mall-web-gateway。
mall-web-gateway 的 pom.xml 内容如下。
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>mall-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>mall-web-gateway</artifactId>
<name>mall-web-gateway</name>
<description>web-网关</description>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<properties>
<springframework.version>4.0.0</springframework.version>
<spring-boot.version>3.0.2</spring-boot.version>
<spring-cloud.version>2022.0.0</spring-cloud.version>
<spring-cloud.version-alibaba>2022.0.0.0</spring-cloud.version-alibaba>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!--nacos注册中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${spring-cloud.version-alibaba}</version>
</dependency>
<!-- nacos配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${spring-cloud.version-alibaba}</version>
</dependency>
<!-- 2020.X.X版本官方重构了bootstrap引导配置的加载方式,需要添加以下依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>${springframework.version}</version>
</dependency>
<!--spring-cloud-starter-gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>${springframework.version}</version>
</dependency>
<!--spring-cloud-starter-openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${springframework.version}</version>
</dependency>
<!--2020版本以后就已经移除了对ribbon的支持,而是使用LoadBalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>${springframework.version}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
</dependencies>
</project>
bootstrap.properties 文件内容如下。
#nacos服务地址
NACOS_ADDR=127.0.0.1:8848
#nacos名称空间
NACOS_NAMESPACE=dev
bootstrap.yml 文件内容如下。
server:
port: 7020
spring:
application:
name: mall-web-gateway
cloud:
nacos:
discovery:
server-addr: ${NACOS_ADDR}
namespace: ${NACOS_NAMESPACE}
group: mall
config:
server-addr: ${NACOS_ADDR}
namespace: ${NACOS_NAMESPACE}
file-extension: yaml
group: mall
extension-configs:
- data-id: mall-web-gateway.yaml
group: mall
refresh: true
Nacos 创建文件名为 mall-web-gateway.yaml 的配置文件,内容如下。
启动类如下。
@Slf4j
@SpringBootApplication(scanBasePackages = {"org.example.gateway"})
@EnableDiscoveryClient
public class MallWebGatewayApplication {
public static void main(String[] args) {
log.info("Begin to start Spring Boot Application");
long startTime = System.currentTimeMillis();
SpringApplication.run(MallWebGatewayApplication.class, args);
long endTime = System.currentTimeMillis();
log.info("End starting Spring Boot Application, Time used: "+ (endTime - startTime) );
}
}
在 org.example.gateway.web 包路径下添加 HelloController,用以测试网关本身服务。
@Slf4j
@RestController
@RequestMapping("web/v1")
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "Hello Spring Cloud Gateway";
}
}
网关工程,项目结果如下所示。
4. URI 配置说明
在 mall-web-gateway.yaml 配置文件中,路由中的 uri 配置,可以直接配置成“http(https)”或“lb”的方式。例如,配置账户服务的 uri,可以配置成“http://localhost:7030”或 “lb://mall-account-service”的形式。配置成“http://localhost:7030”的形式,是访问具体 ip 地址或域名,在微服务这一层次,无负载均衡效果。配置成“lb://mall-account-service”的形式,是以服务名的方式访问,可以达到负载均衡的效果,但是,要切记添加如下依赖,否则,将返回 503(Service Unavailable)状态。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>版本号</version>
</dependency>
5. 网关测试
启动网关服务、账户服务、商品服务、订单服务。
5.1. 测试服务本身
浏览器输入“http://localhost:7020/web/v1/hello”地址,请求成功。
5.2. 测试账户服务
账户服务的端口是 7030,我们通过网关访问账户服务的接口,则端口使用 7020(网关端口),例如,根据账户 id 查询账户接口,postman 输入“http://localhost:7020/web/v1/account/queryById/1693333896005545986”请求地址,结果如下。
5.3. 测试商品服务
商品服务的端口是 7040,我们通过网关访问商品服务的接口,则端口使用 7020(网关端口),例如,根据商品 id 查询商品接口,postman 输入“http://localhost:7020/web/v1/product/queryById/1689299476025978882”请求地址,结果如下。
5.4. 测试订单服务
订单服务的端口是 7050,我们通过网关访问订单服务的接口,则端口使用 7020(网关端口),例如,根据订单 id 查询订单接口,postman 输入“http://localhost:7020/web/v1/order/queryById/1701264883721035778”请求地址,结果如下。
6. 整合 Knife4j
Knife4j 自4.0版本后,提供了一个针对在 Spring Cloud Gateway 网关进行聚合的组件knife4j-gateway。详细介绍可参考官网(链接地址)。
6.1. 版本选择
我们的账户服务、商品服务、订单服务中的 Knife4j,版本为4.3.0,为保持版本统一,我们的 knife4j-gateway 也选择 4.3.0 版本。
6.2. 项目整合
网关 mall-web-gateway 工程的 pom.xml 添加如下依赖。
<!--knife4j-gateway-spring-boot-starter-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-gateway-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
Nacos 创建文件名为 mall-web-gateway-knife4j.yaml 的配置文件,内容如下。
knife4j:
# 聚合swagger文档
gateway:
enabled: true
# 排序规则(tag/operation排序自4.2.0版本新增)
# 取值:alpha-默认排序规则,官方swagger-ui默认实现,order-Knife4j提供的增强排序规则,开发者可扩展x-order,根据数值来自定义排序
tags-sorter: order
operations-sorter: order
# 指定手动配置的模式(默认为该模式)
strategy: manual
routes:
- name: 账户服务
# 真实子服务访问url地址-提供OpenAPI的文档
url: /mall-account-service/v3/api-docs?group=default
service-name: mall-account-service
# 路由前缀
# 兼容OpenAPI3规范在聚合时丢失contextPath属性的异常情况,由开发者自己配置contextPath,Knife4j的前端Ui做兼容处理,与url属性独立不冲突,仅OpenAPI3规范聚合需要,OpenAPI2规范不需要设置此属性,默认为(apiPathPrefix)
context-path: /
order: 2
- name: 商品服务
url: /mall-product-service/v3/api-docs?group=default
service-name: mall-product-service
# 路由前缀
context-path: /
order: 3
- name: 订单服务
url: /mall-order-service/v3/api-docs?group=default
service-name: mall-order-service
# 路由前缀
context-path: /
order: 4
网关 mall-web-gateway bootstrap.yml 添加对 mall-web-gateway-knife4j.yaml 的引用。
6.3. Knife4j 测试
浏览器输入“http://localhost:7020/doc.html#”地址,出现界面如下所示。
左上角下列列表也已加载账户服务、商品服务、订单服务的名称。
当我页面默认加载了账户服务的各组api,选择左上角下拉列表可成功切换服务的api文档,例如,选择商品服务,如下所示。
此时测试“根据id查询商品”接口,也成功返回。
7. 总结
本篇先介绍了 Spring Cloud Gateway 网关工程的搭建。然后对网关工程本身服务及账户服务、商品服务、订单服务进行了测试。在对账户服务、商品服务、订单服务的测过程中,我们始终使用网关端口 7020 进行访问,这验证了使用 Spring Cloud Gateway 可以对服务入口进行统一管理。最后还介绍了在网关工程中整合 Knife4j,并且进行了测试,这也说明了在网关工程中,可以对 api 文档入口进行统一管理。