3. 创建第一个Spring Cloud Gateway工程
前两节我们已经理解了 Spring Cloud Gateway 在微服务体系中的位置:它基于 Spring WebFlux 与 Reactor Netty 构建,是一个响应式、非阻塞的 API 网关。本节不再停留在概念层面,而是从零开始,动手创建一个可以真正转发请求的网关工程。整个过程包含六个关键动作:用 Spring Initializr 生成骨架、引入 spring-cloud-starter-gateway 依赖、编写启动类、配置基础路由、启动服务并验证转发、观察 Netty 服务端启动日志。走完这一遍,你会得到一个最小可运行的网关,它也是后续学习断言、过滤器、限流、熔断等能力的基础载体。
一、用 Spring Initializr 生成项目骨架
推荐使用 Spring Initializr(start.spring.io)生成工程,它能自动处理 Spring Boot 与 Spring Cloud 的版本对应关系,避免手工拼装依赖时出现版本冲突。生成时选择以下参数:
- Project:Maven(也可选 Gradle,本节以 Maven 为例)
- Language:Java
- Spring Boot:选择与目标 Spring Cloud 版本匹配的稳定版,例如 3.2.x
- Group:
com.example,Artifact:gateway-demo - Packaging:Jar,Java:17 或 21
- Dependencies:先只勾选 Gateway,它会自动带入 WebFlux 与 Reactor Netty
下载解压后,工程目录结构大致如下:
gateway-demo
├── pom.xml
└── src
└── main
├── java/com/example/gatewaydemo
│ └── GatewayDemoApplication.java
└── resources
└── application.yml
这里有一个容易踩的坑:网关工程不要再引入 spring-boot-starter-web。因为 Gateway 基于 WebFlux,而 spring-boot-starter-web 会引入 Servlet 容器(Tomcat),两者同时存在会导致应用启动时因 Web 应用类型冲突而失败。Initializr 勾选 Gateway 时不会带入 web starter,这一点是正确的默认行为。
二、确认并理解 gateway 依赖
打开 pom.xml,确认存在如下依赖(版本由 Spring Cloud BOM 统一管理):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
这个 starter 内部聚合了 spring-boot-starter-webflux、reactor-netty、spring-cloud-starter 等模块。也就是说,引入它之后,网关天然运行在 Reactor Netty 之上,而不是 Tomcat。理解这一点,对后面观察启动日志非常关键。
三、编写启动类
启动类本身非常朴素,与普通 Spring Boot 应用没有区别:
package com.example.gatewaydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayDemoApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayDemoApplication.class, args);
}
}
网关的核心能力由自动配置类 GatewayAutoConfiguration 在启动时装配,因此启动类不需要额外注解。真正决定“请求怎么转发”的,是接下来的路由配置。
四、配置基础路由
在 application.yml 中配置一条最简单的路由,把发往网关的 /baidu/** 请求转发到外部站点,用于验证转发链路是否打通:
server:
port: 9000
spring:
application:
name: gateway-demo
cloud:
gateway:
routes:
- id: baidu_route
uri: https://www.baidu.com
predicates:
- Path=/baidu/**
这条配置包含路由的三个必备要素:id 是路由唯一标识;uri 是目标地址;predicates 是匹配条件,这里用 Path 断言匹配路径。当请求 http://localhost:9000/baidu 到达网关时,断言命中,网关就会把请求转发到 https://www.baidu.com/baidu。注意默认情况下路径会原样拼接,若希望去掉前缀,需要额外配置 StripPrefix 过滤器,这属于后续内容。
五、启动并验证请求转发
在工程根目录执行:
mvn spring-boot:run
或者打包后运行:
mvn clean package -DskipTests
java -jar target/gateway-demo-0.0.1-SNAPSHOT.jar
启动成功后,用浏览器或 curl 访问网关:
curl -i http://localhost:9000/baidu
如果返回 HTTP 200 且响应体是百度首页内容,说明请求已经成功经过网关转发到目标站点。若返回 404,通常是断言未命中,需要检查请求路径是否与 Path 规则一致;若返回 502 或连接超时,则要检查 uri 是否可达、网络是否放行。
六、观察 Netty 服务端启动日志
启动过程中,控制台会输出关键日志。最值得关注的是 Netty 相关行:
Netty started on port 9000
Started GatewayDemoApplication in 2.315 seconds
看到 Netty started on port 9000,就证明网关确实运行在 Reactor Netty 之上,而不是 Tomcat。如果日志里出现 Tomcat started on port,说明工程里混入了 Servlet 容器依赖,需要回到 pom.xml 排查。此外,还可以通过 --debug 参数启动,观察 GatewayAutoConfiguration 是否被加载,进一步确认路由自动配置生效。
七、常见问题与判断依据
第一次搭建网关工程时,最容易遇到三类问题。第一类是启动即失败,报 Spring MVC found on classpath 或 Web 应用类型冲突,原因是引入了 spring-boot-starter-web,解决方式是移除该依赖。第二类是启动成功但访问返回 404,说明断言没有命中,需要核对请求路径与 Path 规则是否匹配,注意 /baidu/** 能匹配 /baidu 及其子路径。第三类是返回 502 或超时,说明目标地址不可达,需要检查 uri 是否正确、网络是否放行、目标站点是否可访问。
Netty started on port 9000,以及访问网关端口后能拿到目标服务的响应内容。两者同时满足,说明路由配置与转发链路都已打通。到这里,一个最小可运行的 Spring Cloud Gateway 工程就完成了。它虽然只有一条路由,但已经完整覆盖了“生成工程—引入依赖—编写启动类—配置路由—启动验证—观察日志”的闭环。后续的断言工厂、过滤器、限流、熔断、动态路由等能力,都是在这个骨架上逐步叠加的。