# 依赖注入 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. **避免全局状态**:所有依赖通过注入获取