## `rudi` 目录解析
`rudi` 是项目的**依赖注入(Dependency Injection, DI)框架**,对标 Java Spring IoC 容器,用 Rust 实现了一套完整的 **编译期无侵入、启动期自动注册、运行时延迟加载** 的 Bean 管理容器。
### 目录结构
```
rudi/
├── mod.rs # 模块入口
├── readme.MD # 设计说明文档
│
├── dicontainer/ # 🔴 核心容器层
│ ├── dicontainer.rs # Container 容器实现 + inventory 自动收集
│ ├── direg.rs # 全局注册门面(OnceLock 静态容器)
│ └── mod.rs
│
├── difactroy/ # 🔴 DI 工厂层(代码生成引擎)
│ ├── difactroy.rs # DiFactroy:AST 扫描 + 模板生成
│ ├── difactroy_init.rs # DI 注册(自动生成)
│ ├── difactroy_test.rs # 测试
│ ├── readme.MD # make_di_all 原理详解
│ ├── ruast/ # Rust AST 解析器
│ │ └── ruast.rs # 用 syn 解析源码,查找 impl BaseEntity/Single 的 struct
│ ├── rusingle/ # 单例 Bean 示例
│ │ └── rusingle.rs # 实现 BaseEntitySingle 的示例结构体
│ └── rumulti/ # 多例 Bean 示例
│ └── rumulti.rs # 实现 BaseEntity 的示例结构体
│
├── didto/ # DI 数据传输对象
│ ├── structinfo.rs # StructInfo:结构体元信息(路径、名称、单例/多例等)
│ └── buildstructdto.rs # 构建结构体的 DTO
│
├── ditemplate/ # 模板解析
│ └── parsetemplate.rs # 读取模板文件 + 生成 DI 注册代码
│
├── ditrait/ # Bean 注册表 Trait 定义
│ └── ditrait.rs # BeanRegistry trait(register / get_bean 等)
│
├── diconst/ # 常量定义
│ └── diconst.rs # 模板文件路径常量
│
└── diexample.rs # 示例 Bean(DiExample)
```
---
### 核心设计:三层架构
```
┌─────────────────────────────────────────────────────────────┐
│ 1. 编译期 / 开发期 │
│ │
│ ruast (syn AST 解析) │
│ │ 扫描 src/ 下所有 .rs 文件 │
│ │ 查找 impl BaseEntity for Xxx / impl BaseEntitySingle │
│ │ 识别 #[derive(Default)] │
│ ▼ │
│ DiFactroy (代码生成引擎) │
│ │ 读取模板 struct_init.template │
│ │ 替换模板变量 → 生成 _init.rs 文件 │
│ │ 自动更新 mod.rs │
│ ▼ │
│ 生成 *_init.rs 文件(如 person_init.rs) │
├─────────────────────────────────────────────────────────────┤
│ 2. 启动期(编译时) │
│ │
│ #[ctor(unsafe)] + inventory::submit! │
│ │ 所有 *_init.rs 中的 register_bean_xxx() 自动注册 │
│ │ → inventory::collect!(Reg) 收集所有注册项 │
│ │ → bootstrap() 一次性注入到 Container │
│ ▼ │
│ Container { items: HashMap<String, Entry> } │
├─────────────────────────────────────────────────────────────┤
│ 3. 运行期 │
│ │
│ direg::get_bean::<T>(key) / find_bean_xxx() │
│ │ 按需获取 Bean(首次懒加载,之后复用) │
│ ▼ │
│ Arc<T> → 业务代码使用 │
└─────────────────────────────────────────────────────────────┘
```
---
### 1. `dicontainer` — 核心容器
#### `Container` — Bean 存储引擎
[dicontainer.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/dicontainer/dicontainer.rs) 实现了两种存储模式:
```rust
enum Entry {
Factory(Box<dyn Fn() -> Box<dyn Any> + Send + Sync>), // 多例:每次新建
Singleton {
factory: Box<dyn Fn() -> Box<dyn Any> + Send + Sync>,
instance: Mutex<Option<Arc<dyn Any + Send + Sync>>>, // 单例:缓存
},
}
```
| `register(key, factory)` | 注册多例工厂 |
| `register_singleton(key, factory)` | 注册单例工厂 |
| `get::<T>(key)` | 获取多例(每次 new) |
| `get_singleton::<T>(key)` | 获取单例(返回 `Arc<T>`,懒加载) |
| `get_bean::<T>(key)` | **统一入口**:自动判断单例/多例 |
| `is_singleton(key)` | 判断是否为单例 |
#### `inventory` 自动收集机制
```rust
pub struct Reg {
pub name: &'static str,
pub apply: fn(&mut Container),
}
inventory::collect!(Reg); // 编译期收集所有 submit! 的注册项
pub fn bootstrap(container: &mut Container) {
for reg in inventory::iter::<Reg> {
(reg.apply)(container); // 启动时一次性注入
}
}
```
提供两个便捷宏:
```rust
register_singleton!("key", MyType, MyType::new); // 单例注册
register_transient!("key", MyType, MyType::new); // 多例注册
```
#### `direg` — 全局注册门面
[direg.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/dicontainer/direg.rs) 用 `OnceLock<RwLock<Container>>` 实现线程安全的全局静态容器:
```rust
static GLOBAL: OnceLock<RwLock<Container>> = OnceLock::new();
pub fn register<F, T>(key, factory) // 全局注册多例
pub fn register_singleton<F, T>(key, f) // 全局注册单例
pub fn get<T>(key) -> Option<T> // 全局获取多例
pub fn get_singleton<T>(key) -> Option<Arc<T>> // 全局获取单例
pub fn get_bean<T>(key) -> Option<Arc<T>> // 全局获取 Bean(统一入口)
```
---
### 2. `difactroy` — DI 代码生成引擎
[difactroy.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/difactroy/difactroy.rs) 是整个框架最核心的自动化能力,对标 Java Spring 的包扫描 + 注解处理。
**核心流程:**
```
make_di_all("./src")
│
├── 1. fill_template()
│ 读取 config/rudi/template/struct_init.template
│
├── 2. parse_all_files("./src")
│ 遍历所有 .rs 文件
│ → RuAst::find_entity_all() AST 解析
│ ├── 找 impl BaseEntity for Xxx → 多例
│ └── 找 impl BaseEntitySingle for Xxx → 单例
│ → 填充 StructInfo 列表
│
├── 3. build_init(stru)
│ 模板变量替换:
│ {{StructPkg}} → rudomain::rudb::dbentity::dbexample
│ {{RuSingle}} → Person
│ {{register_singleton}} → register / register_singleton
│ ...
│
├── 4. create_init(iniFile, content)
│ 写入 person_init.rs 文件
│
└── 5. edit_mod(stru)
自动更新 mod.rs 添加 pub mod person_init;
```
**关键 API:**
| `make_di()` | 为 `./src` 下所有结构体生成 DI 代码 |
| `make_di_one(name)` | 为指定结构体生成 |
| `make_di_force()` | 强制覆盖已存在的 `_init.rs` |
| `list_di()` | 列出所有可注入的结构体 |
| `unmake_di_one()` | 移除 DI 代码(预留) |
#### `ruast` — Rust AST 解析器
[ruast.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/difactroy/ruast/ruast.rs) 基于 `syn` 库解析 Rust 源码:
| 查找 `impl BaseEntity for Xxx` | `find_base_entity()` |
| 查找 `impl BaseEntitySingle for Xxx` | `find_base_entity_single()` |
| 查找 `#[derive(Default)]` | `find_derive_default()` / `has_derive_default()` |
| 综合查找 | `find_entity_all()` → 返回 `Vec<StructInfo>` |
---
### 3. `didto` — 结构体元信息
[structinfo.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/didto/structinfo.rs) 记录每个 Bean 的完整元信息:
```rust
pub struct StructInfo {
pub pathFile: String, // 源文件路径
pub pathPkg: String, // 包路径
pub structName: String, // 结构体名称
pub structPkg: String, // 完整包路径(如 rudomain::rudb::dbentity::dbexample)
pub ifSingle: bool, // 是否单例
pub ifDefault: bool, // 是否有 Default 实现
pub structIniFile: String, // 生成的 _init.rs 文件名
pub existIniFile: bool, // _init.rs 是否已存在
pub single_bean_name: String,// 全局唯一 Bean 名称(含 UUID)
pub modFile: String, // mod.rs 路径
}
```
核心方法:`build_single_bean_name()` 生成 `*包路径:结构体名:UUID(:single)` 格式的全局唯一标识。
---
### 4. `ditemplate` — 模板引擎
[parsetemplate.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/ditemplate/parsetemplate.rs) 读取模板文件并替换变量。
模板文件 [struct_init.template](file:///E:/soft/gitee.com/ruwebframe/config/rudi/template/struct_init.template):
```rust
// pkg {{StructPkg}}
use crate::rudi::dicontainer::direg;
use crate::{{StructPkg}}::{{RuSingle}};
#[ctor(unsafe)]
pub fn init() {
register_bean_{{rusingle}}();
}
const SINGLE_BEAN_NAME: &str = "{{SINGLE_BEAN_NAME}}";
pub fn find_bean_{{rusingle}}() -> Option<Arc<{{RuSingle}}>> {
direg::get_bean::<{{RuSingle}}>(SINGLE_BEAN_NAME)
}
pub fn register_bean_{{rusingle}}() {
direg::{{register_singleton}}(SINGLE_BEAN_NAME, {{RuSingle}}::new);
}
```
替换变量后生成如 `person_init.rs` 的完整 DI 注册代码。
---
### 5. `ditrait` — Bean 注册表 Trait
[ditrait.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/ditrait/ditrait.rs) 定义了容器必须实现的接口:
```rust
pub trait BeanRegistry {
fn register<F, T>(&mut self, key: &str, factory: F);
fn register_singleton<F, T>(&mut self, key: &str, factory: F);
fn get_bean<T: Any + Send + Sync>(&self, key: &str) -> Option<Arc<T>>;
}
```
---
### 完整使用流程
```
1. 定义结构体
#[derive(Clone, Default)]
pub struct MyService { ... }
impl BaseEntitySingle for MyService {} // 标记为单例 Bean
2. 运行代码生成
rucmd rudi all
→ 扫描所有 .rs 文件
→ 找到 impl BaseEntitySingle for MyService
→ 生成 my_service_init.rs(含 ctor 自动注册 + find_bean 函数)
3. 程序启动
→ ctor 自动执行 register_bean_myservice()
→ direg::register_singleton("...", MyService::new)
→ 注入到全局 Container
4. 业务代码使用
let svc = my_module::find_bean_myservice().unwrap();
svc.do_something();
```
---
### 架构定位
```
┌─────────────────────────┐
│ rudi (DI层) │
│ 对标 Spring IoC Container │
└────────────┬────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ rubase │ │ *_init.rs │ │ rucmd │
│ BaseEntity│ │ (自动生成) │ │ rudi命令 │
│ 标记Bean │ │ ctor自动注册 │ │ 触发生成 │
└──────────┘ └──────────────┘ └──────────┘
```
**总结**:`rudi` 是一个完整的 DI 框架,包含三个核心能力:
**① 容器存储**(Container + direg,线程安全的全局 Bean 管理)、
**② 代码生成**(DiFactroy + RuAst,自动扫描源码生成 `_init.rs` 注册代码)、
**③ 自动注册**(inventory + ctor,编译期收集 + 启动期注入)。
通过 `impl BaseEntity` / `impl BaseEntitySingle` 标记 Bean,
运行 `rucmd rudi all` 即可一键生成所有 DI 代码,实现类似 Spring 的自动装配体验。
## `rudi` 使用示例
### 第一步:定义 Bean(结构体)
rudi 支持两种 Bean 模式:**单例** 和 **多例**。
#### 方式一:单例 Bean(全局唯一实例)
```rust
// 文件: src/rudi/difactroy/rusingle/ru_single
use crate::rubase::ruentity;
use crate::rulog::rulog;
#[derive(Clone, Debug, Default)]
pub struct RuSingle {}
impl ruentity::BaseEntitySingle for RuSingle {} // ⭐ 关键标记:单例模式
impl RuSingle {
pub fn new() -> Self {
let mut s = RuSingle {};
s.init();
s
}
pub fn execute(&self) -> String {
rulog::info("RuSingle execute");
String::from("RuSingle execute result")
}
fn init(&mut self) {
rulog::info("RuSingle init");
}
}
impl Drop for RuSingle {
fn drop(&mut self) {
rulog::info("RuSingle Drop");
}
}
```
#### 方式二:多例 Bean(每次获取新建实例)
```rust
// 文件: src/rudi/difactroy/rumulti/ru_multi
use rudi::Transient;
use serde::{Deserialize, Serialize};
use crate::rubase::{ruentity, BaseEntity};
use crate::rulog::rulog;
#[Transient] // ⭐ 可选属性宏
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct RuMulti {}
impl BaseEntity for RuMulti {} // ⭐ 关键标记:多例模式
impl RuMulti {
pub fn new() -> Self {
RuMulti {}
}
pub fn execute(&self) -> String {
rulog::info("RuMulti execute");
String::from("RuMulti execute result")
}
}
```
#### 方式三:复杂业务 Bean(如 Database)
```rust
// 文件: src/database/database.rs
use crate::rubase::BaseEntitySingle;
#[derive(Clone, Debug)]
pub struct Database {
pub gorm: Gorm,
pub datasource: DataSource,
}
impl BaseEntitySingle for Database {} // 单例模式
impl Database {
pub fn new() -> Self {
let config = rucfg::find_bean_ruconfig().unwrap().read();
Database {
gorm: config.gorm,
datasource: config.datasource,
}
}
pub fn conn(&self) -> Result<postgres::Client, postgres::Error> {
// 创建数据库连接
}
}
```
---
### 第二步:生成 DI 代码
运行命令行工具,扫描源码并自动生成 `_init.rs` 文件:
```bash
# 列出所有可注入的 Bean
rucmd rudi list
# 为所有 Bean 生成 DI 代码
rucmd rudi all
# 为指定 Bean 生成(如 Person)
rucmd rudi Person
```
执行后,会在结构体同目录下自动生成 `xxx_init.rs` 文件。
---
### 第三步:自动生成的 `_init.rs` 文件
#### 单例 Bean 的生成代码([rusingle_init.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/difactroy/rusingle/rusingle_init.rs))
```rust
use std::sync::Arc;
use ctor::ctor;
use crate::rudi::dicontainer::direg;
use crate::rudi::difactroy::rusingle::rusingle::RuSingle;
#[ctor(unsafe)] // ⭐ 程序启动时自动执行
pub fn init() {
register_bean_rusingle();
}
const SINGLE_BEAN_NAME: &str =
"*rudi::difactroy::rusingle::rusingle:RuSingle:743b89f8-...:single}";
pub fn find_bean_rusingle() -> Option<Arc<RuSingle>> { // ⭐ 获取 Bean
direg::get_bean::<RuSingle>(SINGLE_BEAN_NAME)
}
pub fn register_bean_rusingle() { // ⭐ 注册 Bean
direg::register_singleton(SINGLE_BEAN_NAME, RuSingle::default);
}
```
#### 多例 Bean 的生成代码([rumulti_init.rs](file:///E:/soft/gitee.com/ruwebframe/src/rudi/difactroy/rumulti/rumulti_init.rs))
```rust
use std::sync::Arc;
use ctor::ctor;
use crate::rudi::dicontainer::direg;
use crate::rudi::difactroy::rumulti::rumulti::RuMulti;
#[ctor(unsafe)]
pub fn init() {
register_bean_rumulti();
}
const SINGLE_BEAN_NAME: &str =
"*rudi::difactroy::rumulti::rumulti:RuMulti:84f30326-...";
pub fn find_bean_rumulti() -> Option<Arc<RuMulti>> {
direg::get_bean::<RuMulti>(SINGLE_BEAN_NAME)
}
pub fn register_bean_rumulti() {
direg::register(SINGLE_BEAN_NAME, RuMulti::new); // ⭐ 多例用 register
}
```
**关键区别**:
| 注册方法 | `register_singleton` | `register` |
| 每次获取 | 返回同一个实例 | 返回新实例 |
| 构造函数 | `Default::default()` | `new()` |
---
### 第四步:业务代码中使用
#### 4.1 获取单例 Bean
```rust
#[test]
fn test_use_single() {
// 方式1:直接获取并调用
let rs = rusingle::find_bean_rusingle().unwrap();
let result = rs.execute();
assert_eq!(result, "RuSingle execute result");
// 方式2:多次获取,验证是同一个实例
let a = rusingle::find_bean_rusingle().unwrap();
let b = rusingle::find_bean_rusingle().unwrap();
// a 和 b 指向同一个实例(单例)
}
```
#### 4.2 获取多例 Bean
```rust
#[test]
fn test_use_multi() {
let rs = rumulti::find_bean_rumulti().unwrap();
let result = rs.execute();
println!("{}", result);
// 每次获取都是新实例
let a = rumulti::find_bean_rumulti().unwrap();
let b = rumulti::find_bean_rumulti().unwrap();
// a 和 b 是不同的实例
}
```
#### 4.3 实际项目中的使用模式
```rust
use crate::database;
use crate::rucfg;
// 获取数据库连接(单例)
let db = database::find_bean_database().unwrap();
for row in db.conn().unwrap().query("SELECT * FROM users LIMIT 3", &[]) {
println!("{:?}", row.get::<_, i32>(0));
}
// 获取配置(多例,每次重新解析)
let config = rucfg::find_bean_ruconfig().unwrap().read();
println!("{:?}", config.redis);
// 获取 Redis 客户端(单例)
let redis = database::find_bean_redisclient().unwrap();
redis.set_key("my_key", "my_value").unwrap();
let val = redis.get_key("my_key").unwrap();
// 获取加密工具(单例)
let encrypted = ruenc::find_bean_ruenc().unwrap().enc("password");
let decrypted = ruenc::find_bean_ruenc().unwrap().dec(&encrypted);
```
---
### 完整流程总结
```
┌─────────────────────────────────────────────────────────────────┐
│ 1. 定义 struct │
│ #[derive(Clone, Debug, Default)] │
│ pub struct MyService {} │
│ impl BaseEntitySingle for MyService {} ← 标记 Bean 类型 │
│ impl MyService { pub fn new() -> Self { ... } } │
├─────────────────────────────────────────────────────────────────┤
│ 2. 生成 DI 代码 │
│ $ rucmd rudi all │
│ → 扫描所有 .rs 文件 │
│ → 找到 impl BaseEntity/BaseEntitySingle 的 struct │
│ → 生成 my_service_init.rs │
├─────────────────────────────────────────────────────────────────┤
│ 3. 自动生效(编译时) │
│ #[ctor(unsafe)] pub fn init() { ... } ← 程序启动自动注册 │
│ → direg::register_singleton(key, factory) │
├─────────────────────────────────────────────────────────────────┤
│ 4. 业务使用 │
│ let svc = my_module::find_bean_myservice().unwrap(); │
│ svc.do_work(); │
└─────────────────────────────────────────────────────────────────┘
```
**核心要点**:
- **标记**:`impl BaseEntitySingle` = 单例,`impl BaseEntity` = 多例
- **生成**:`rucmd rudi all` 一键生成
- **注册**:`#[ctor]` 启动自动注册,零侵入
- **使用**:`find_bean_xxx()` 获取,一行代码搞定