作为资深的 Java 开发者,我们闭着眼睛都能用 Spring Boot 搭建起一个 RESTful API。@RestController
、@GetMapping
、@Autowired
…这些注解如同魔法咒语,Spring 的自动配置和依赖注入为我们处理了大量底层细节,让我们能以惊人的速度进行开发。
现在,欢迎来到 Rust 的 Web 开发世界。这里没有“魔法”,没有运行时反射,也没有庞大的依赖注入容器。Rust 的哲学是明确、显式和编译期安全。你可能会失去一些 Spring Boot 的“开箱即用”的便利,但你将换来的是无与伦比的性能、极致的资源效率和坚如磐石的可靠性。
在本章,我们将介绍构建 Rust Web 服务的三巨头,并搭建一个简单的 API:
- 运行时(Runtime)-
Tokio
: 它是 Rust 异步生态的事实标准。可以把它想象成驱动 Spring WebFlux 的 Netty 事件循环,或者是嵌入式 Tomcat 底层的线程池和 I/O 管理器。 - Web 框架 -
Axum
: 一个现代、模块化的 Web 框架,与Tokio
无缝集成。它就是 Rust 世界的 Spring Web MVC / WebFlux,负责路由、请求处理、中间件等。 - 序列化/反序列化 -
Serde
: Rust 的“Jackson”。它是一个极其强大和高效的库,用于将 Rust 的数据结构与各种数据格式(如 JSON)进行相互转换。
async
/.await
:Rust 异步编程的核心
现代 Web 服务需要处理成千上万的并发连接。阻塞每一个请求的线程是不可行的。因此,和 Spring WebFlux 一样,现代 Rust Web 开发也是基于异步非阻塞模型的。
async fn
: 将一个函数标记为异步函数。调用它不会立即执行,而是返回一个**Future
**。这非常类似 Java 中的CompletableFuture
或 Project Reactor 中的Mono
。它代表一个“未来会完成的计算”。.await
: 当你需要等待一个Future
的结果时,使用.await
。它会“暂停”当前任务的执行,让出线程去执行其他任务,直到Future
完成后再回来继续。这避免了线程的阻塞。
而 Tokio
,就是那个负责调度和执行成千上万个 Future
的强大引擎。
项目设置:迎接 Cargo 的高光时刻
让我们用 Cargo 创建一个新项目,并在 Cargo.toml
中添加我们的“三巨头”依赖:
[dependencies]
# 异步运行时
tokio = { version = "1", features = ["full"] }
# Web 框架
axum = "0.7"
# 序列化/反序列化库
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
注意 features
标志,这是 Cargo 的一个强大功能,它允许我们只引入一个库中我们真正需要的部分,从而减小最终编译产物的大小。
实战:构建一个简单的用户 API
我们的目标是创建一个简单的 API,可以创建用户和获取用户列表。
第一步:定义模型(Model)和 Serde
首先,定义我们的 User
数据结构。这非常像在 Java 中创建一个 POJO。
use serde::{Deserialize, Serialize};
// derive 宏是 Rust 的编译期代码生成魔法
// 它会自动为 User 实现序列化和反序列化的能力
#[derive(Serialize, Deserialize, Debug, Clone)]
struct User {
id: u64,
username: String,
}
#[derive(Serialize, Deserialize)]
这个注解,就是 Serde
的威力所在。它会在编译期自动为 User
生成转换为 JSON 和从 JSON 创建实例的代码。这实现了和 Java Jackson 库类似的功能,但它不是在运行时通过反射,而是在编译期完成,因此性能更高。
第二步:创建处理器(Handler)——@RestController
的替代品
在 Axum 中,处理器就是一个个返回 Future
的异步函数。
use axum::{Json, response::IntoResponse};
use std::sync::Arc;
use tokio::sync::Mutex;
// 我们的“内存数据库”
type Db = Arc<Mutex<Vec<User>>>;
// 获取所有用户 - 类似 @GetMapping("/users")
async fn get_users(db: Db) -> impl IntoResponse {
let users = db.lock().await;
Json(users.clone())
}
// 创建用户 - 类似 @PostMapping("/users")
async fn create_user(
Json(payload): Json<User>, // Axum 的提取器,自动从请求体中反序列化 JSON
db: Db,
) -> impl IntoResponse {
let mut users = db.lock().await;
users.push(payload);
(http::StatusCode::CREATED, "User created")
}
Json<T>
是 Axum 的一个提取器(Extractor)。当它作为参数时 (Json(payload)
),它会尝试将请求体(Request Body)中的 JSON 反序列化成User
类型。如果失败,Axum 会自动返回一个400 Bad Request
错误。当它作为返回值时,它会将你的数据结构序列化成 JSON 响应。
第三步:定义路由(Router)——@RequestMapping
的替代品
我们需要将 URL 路径和 HTTP 方法映射到我们的处理器函数上。
use axum::{routing::{get, post}, Router};
fn app_router(db: Db) -> Router {
Router::new()
.route("/users", get(get_users).post(create_user))
.with_state(db) // 将数据库状态注入到处理器中
}
Router::new()
创建了一个新的路由器,.route()
方法清晰地定义了路径和方法的映射关系。
第四步:启动服务器
最后,在 main
函数中,我们使用 Tokio
来启动我们的服务。
#[tokio::main]
async fn main() {
// 初始化我们的内存数据库
let db = Db::default();
// 创建路由器
let app = app_router(db);
// 绑定地址和端口
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
// 启动服务
axum::serve(listener, app).await.unwrap();
}
#[tokio::main]
宏为我们设置好了整个异步运行时。整个启动过程代码非常简短和直白。
对决:Spring Boot vs. Rust/Axum
对比维度 | Spring Boot | Rust + Axum | 评述 |
---|---|---|---|
开发模型 | 注解驱动,依赖注入,运行时“魔法” | 函数式,显式组合,编译期生成 | Spring 开发速度快,Rust 更明确,无隐藏逻辑。 |
内存占用 | 高 (JVM + Spring 上下文,通常 100MB+ 起步) | 极低 (单个二进制文件,通常 < 10MB) | Rust 在容器化和 Serverless 场景中优势巨大。 |
启动速度 | 较慢 (秒级) | 极快 (毫秒级) | |
性能/延迟 | 良好 (JIT 预热后性能不错,但有 GC 停顿风险) | 极致 (接近 C++ 的原生性能,无 GC 停顿) | Rust 提供稳定、可预测的低延迟。 |
编译产物 | .jar 文件 + 需要 JVM 才能运行 |
单个、无依赖的二进制可执行文件 | Rust 的部署极其简单,一个文件扔上去就能跑。 |
生态系统 | 极其成熟 (Spring Data, Security, Cloud…) | 快速发展中 (但需要手动组合更多库) | Spring 的生态是其最大优势,提供了全方位的解决方案。 |
结论: Rust 舍弃了 Spring 的运行时便利性和“魔法”,换来的是在性能、资源占用和部署简易性上的绝对优势。这是一种用“明确性”换取“极致性能”的权衡。
本章小结
我们成功地使用 Tokio
、Axum
和 Serde
构建了一个高性能、资源占用极低的异步 Web 服务。我们看到了 Rust 如何通过显式的函数和组合,来完成 Spring Boot 中由注解和框架“魔法”所做的工作。
这证明了 Rust 不仅仅是一门系统编程语言,它同样有能力在 Web 后端这个 Java 的传统优势领域中,提供一个极具竞争力的、现代化的选择。
你已经走完了从 Java 到 Rust 的所有核心学习路径。从内存安全到无畏并发,再到今天的 Web 实战,你已经具备了用 Rust 解决实际问题的能力。
在专栏的最后一章 《未来之路——Rust 生态圈漫游指南与持续学习》 中,我们将一起眺望远方,看看 Rust 世界里还有哪些激动人心的领域等待着我们去探索。