编译时扫描机制

为什么需要编译时扫描

传统 Rust Web 框架在运行时构建路由表。rust-webx 选择在**编译期**收集元数据,带来:

- 启动时零反射开销 - 遗漏注册在编译期暴露 - OpenAPI 文档可从同一元数据生成

inventory 机制

框架使用 `inventory` crate 实现编译时收集:

// 宏展开后大致等价于:
inventory::submit! {
    RouteEntry {
        method: HttpMethod::Get,
        path: "/hello",
        request_type: TypeId::of::<HelloRequest>(),
        response_type: ...,
        ...
    }
}

每个 `#[get]`、`#[post]` 等宏在展开时向 `inventory` 提交一条 `RouteEntry`。

Host::build() 扫描流程

graph TD
    A[Host::build] --> B[inventory::iter 遍历 RouteEntry]
    B --> C[构建 Trie Router + RouteDispatch]
    C --> D[inventory::iter 遍历 HandlerRegistration]
    D --> E[构建 HandlerCache]
    E --> F[assert_route_configuration_valid]
    F --> G[构建 ServiceProvider + set_global_provider]
    G --> H[生成 OpenAPI spec]

路由收集

`#[get("/api/users/{id}")]` 宏展开时记录:

| 字段 | 值 | |------|---| | HTTP Method | GET | | Path Pattern | `/api/users/{id}` | | Request Type | `GetUserRequest` | | Response Type | `UserDto` | | Authorize | 可选的角色/权限要求 |

Handler 收集

`#[handler]` / `#[handler(inject)]` 宏展开时向 inventory 提交 `HandlerRegistration`:

| 字段 | 值 | |------|---| | Request Type | `HelloRequest` | | Response Type | `String` | | Handler Type | `HelloHandler` | | Factory | 构造 Handler(`Default` 或 DI 注入) |

HTTP 分发通过 `HandlerCache` 查找上述注册项,**不**通过 DI 查找 `dyn IRequestHandler`。

#[handler(inject)] 与 #[inject]

当 Handler 需要 DI 注入时:

#[inject]
pub struct LoginHandler {
    ctx: Arc<Mutex<DbContext>>,
}

#[handler(inject)]
#[async_trait]
impl IRequestHandler<LoginRequest, AuthResponse> for LoginHandler { ... }

`#[inject]` 向 DI 容器注册构造逻辑;`#[handler(inject)]` 标记该 Handler 走注入路径而非 Default。

授权元数据收集

`#[authorize(role = "admin")]` 在编译期收集授权要求;`collect_authorizers()` 在 `build()` 时可构建 `ResourceAuthorization` 策略对象。

> **注意:** `add_authentication()` 仅注册 JWT 中间件,**不会**自动挂载 `resource_auth_middleware`。路由级授权在 `StubEndpoint` 内执行;全局 Resource Auth 中间件需手动添加。详见 [资源授权](../09-auth-security/resource-authorization.md)。

注意事项

1. **链接时收集**:`inventory` 依赖链接时合并,确保 Handler 所在 crate 被链接(未被 dead_code 优化掉) 2. **跨 crate**:子 crate 的路由需在该 crate 中被引用(`mod handlers;`)才会参与链接 3. **测试 binary**:集成测试需 `use` 相关模块以触发 inventory 收集

小结

编译时扫描是 rust-webx「零配置」体验的技术基石。你写 `#[get]` + `#[handler]`,框架在 `build()` 时自动完成路由表、HandlerCache 关联与文档生成;配置不一致时启动即 panic。

下一章:[请求即端点](../05-request-pattern/INDEX.md)