包含 VitePress 文档站完整源码及全新自定义首页设计: - 自定义首页组件 (Home.vue):Hero + 终端动效 + 核心能力 + 架构展示 + 快速开始 + CTA - 自定义 Layout.vue:首页/文档页布局切换 - 金铜色品牌主题样式 - 完整文档页面(指南、API、更新日志、演示、社区) - SEO 配置(sitemap、robots、meta 标签)
112 lines
2.5 KiB
Markdown
112 lines
2.5 KiB
Markdown
# 依赖注入
|
||
|
||
MengStack 使用 [uber-go/fx](https://github.com/uber-go/fx) 进行依赖注入,自动管理组件的生命周期和依赖关系。
|
||
|
||
## 为什么用依赖注入?
|
||
|
||
没有 DI 框架时,组装应用需要手动 wiring:
|
||
|
||
```go
|
||
// 手动 wiring — 容易遗漏,难以维护
|
||
db := database.New(cfg.DB)
|
||
rdb := cache.New(cfg.Redis)
|
||
repo := infrastructure.NewUserRepo(db)
|
||
svc := application.NewService(repo, rdb, cfg.JWT)
|
||
handler := interfaces.NewHandler(svc)
|
||
```
|
||
|
||
使用 fx 后,依赖关系由框架自动解析:
|
||
|
||
```go
|
||
// fx 自动解析依赖
|
||
fx.Provide(
|
||
database.New,
|
||
cache.New,
|
||
application.NewService,
|
||
interfaces.NewHandler,
|
||
)
|
||
```
|
||
|
||
## fx.Module 组织
|
||
|
||
每个模块通过 `fx.Module` 声明自己的依赖:
|
||
|
||
```go
|
||
// internal/modules/auth/interfaces/module.go
|
||
var Module = fx.Module("auth",
|
||
fx.Provide(
|
||
infrastructure.NewUserRepository,
|
||
infrastructure.NewTokenRepository,
|
||
application.NewService,
|
||
NewHandler,
|
||
NewAuthMiddleware,
|
||
SetupRoutes,
|
||
),
|
||
)
|
||
```
|
||
|
||
主应用组装所有模块:
|
||
|
||
```go
|
||
// internal/app/app.go
|
||
func NewApp() *fx.App {
|
||
return fx.New(
|
||
fx.Provide(config.Load, logger.New),
|
||
database.Module,
|
||
cache.Module,
|
||
authinterfaces.Module,
|
||
Module,
|
||
)
|
||
}
|
||
```
|
||
|
||
## 生命周期管理
|
||
|
||
fx 自动管理组件的启动和停止顺序:
|
||
|
||
```go
|
||
func newServer(lc fx.Lifecycle, engine *gin.Engine) *http.Server {
|
||
srv := &http.Server{Addr: ":2222", Handler: engine}
|
||
|
||
lc.Append(fx.Hook{
|
||
OnStart: func(ctx context.Context) error {
|
||
go srv.ListenAndServe()
|
||
return nil
|
||
},
|
||
OnStop: func(ctx context.Context) error {
|
||
return srv.Shutdown(ctx)
|
||
},
|
||
})
|
||
|
||
return srv
|
||
}
|
||
```
|
||
|
||
fx 会确保:
|
||
- **OnStart** 按依赖顺序执行(先数据库,后应用)
|
||
- **OnStop** 按逆序执行(先应用,后数据库)
|
||
|
||
## 参数注入
|
||
|
||
通过函数参数声明依赖,fx 自动注入:
|
||
|
||
```go
|
||
func newEngine(
|
||
cfg *config.Config, // fx 自动提供
|
||
log *zap.Logger, // fx 自动提供
|
||
db *gorm.DB, // fx 自动提供
|
||
rdb *redis.Client, // fx 自动提供
|
||
authHandler *Handler, // fx 自动提供
|
||
authMW gin.HandlerFunc, // fx 自动提供
|
||
) *gin.Engine {
|
||
// ...
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
1. **构造函数注入**:通过 `fx.Provide` 注册构造函数
|
||
2. **接口传递**:尽量传递接口而非具体实现
|
||
3. **模块隔离**:每个业务模块声明自己的 `fx.Module`
|
||
4. **避免全局状态**:所有依赖通过注入获取
|