Skip to content

依赖注入

VEF Framework 基于 Uber FX 实现依赖注入,自动管理组件的生命周期和依赖关系。

基本概念

依赖注入(Dependency Injection,DI)是一种设计模式,通过外部注入依赖而不是在组件内部创建依赖,实现松耦合架构。

传统方式 vs 依赖注入

go
// Traditional approach - tight coupling
// The service creates its own dependencies
type UserService struct {
    db *sql.DB
}

func NewUserService() *UserService {
    // Service creates its own database connection
    db, _ := sql.Open("postgres", "...")
    return &UserService{db: db}
}

// Dependency Injection approach - loose coupling
// Dependencies are injected from outside
type UserService struct {
    db orm.Db
}

func NewUserService(db orm.Db) *UserService {
    // Database is injected, not created internally
    return &UserService{db: db}
}

注册组件

VEF Framework 提供了多种方式注册组件:

使用 vef.Provide

注册普通组件(服务、仓库等):

go
package main

import (
    "my-app/internal/services"
    "github.com/ilxqx/vef-framework-go/vef"
)

func main() {
    vef.Run(
        // Register a service constructor
        vef.Provide(services.NewUserService),
        vef.Provide(services.NewOrderService),
    )
}

使用 vef.ProvideResource

注册 API 资源:

go
package main

import (
    "my-app/internal/resources"
    "github.com/ilxqx/vef-framework-go/vef"
)

func main() {
    vef.Run(
        // Register API resources
        vef.ProvideResource(resources.NewUserResource),
        vef.ProvideResource(resources.NewOrderResource),
    )
}

使用 vef.Invoke

在应用启动时执行初始化逻辑:

go
package main

import (
    "github.com/ilxqx/vef-framework-go/event"
    "github.com/ilxqx/vef-framework-go/log"
    "github.com/ilxqx/vef-framework-go/vef"
)

func main() {
    vef.Run(
        // Execute initialization logic at startup
        vef.Invoke(func(bus event.Bus, logger log.Logger) {
            // Subscribe to events
            bus.Subscribe("user.created", func(ctx context.Context, e event.Event) {
                logger.Infof("User created: %s", e.Meta()["userId"])
            })
        }),
    )
}

构造函数规范

依赖注入的构造函数需要遵循以下规范:

基本构造函数

go
// Constructor with dependencies as parameters
// Returns the constructed instance
func NewUserService(db orm.Db, logger log.Logger) *UserService {
    return &UserService{
        db:     db,
        logger: logger,
    }
}

带错误返回的构造函数

go
// Constructor that may fail
// Returns instance and error
func NewUserService(db orm.Db) (*UserService, error) {
    if db == nil {
        return nil, errors.New("database connection is required")
    }
    return &UserService{db: db}, nil
}

返回接口的构造函数

go
// Constructor returning an interface
// Allows for easier testing and mocking
type UserRepository interface {
    FindById(ctx context.Context, id string) (*User, error)
}

func NewUserRepository(db orm.Db) UserRepository {
    return &userRepositoryImpl{db: db}
}

可注入的依赖

VEF Framework 提供了多种可注入的依赖:

核心依赖

类型说明
orm.Db数据库连接
log.Logger日志记录器
event.Bus事件总线
cache.Cache[T]缓存服务
storage.Service文件存储服务
cron.Scheduler定时任务调度器
vef.Lifecycle生命周期管理

请求级依赖

在 API 处理器中,可以注入请求级依赖:

go
// Request-scoped dependencies in handlers
func (r *UserResource) CustomHandler(
    ctx fiber.Ctx,           // HTTP context
    db orm.Db,               // Database connection
    params UserParams,       // Request parameters (auto-parsed)
    principal *security.Principal, // Current user (if authenticated)
) error {
    // Handler implementation
    return result.Ok(data).Response(ctx)
}

模块化组织

使用模块组织相关的依赖:

go
// internal/modules/user/module.go
package user

import (
    "my-app/internal/modules/user/resources"
    "my-app/internal/modules/user/services"
    "github.com/ilxqx/vef-framework-go/vef"
)

// Module returns all dependencies for the user module
func Module() vef.ModuleFunc {
    return vef.Module(
        // Register services
        vef.Provide(services.NewUserService),
        vef.Provide(services.NewUserValidator),
        
        // Register resources
        vef.ProvideResource(resources.NewUserResource),
    )
}

在主程序中组合模块:

go
// cmd/main.go
package main

import (
    "my-app/internal/modules/user"
    "my-app/internal/modules/order"
    "github.com/ilxqx/vef-framework-go/vef"
)

func main() {
    vef.Run(
        // Compose modules in dependency order
        user.Module(),
        order.Module(),
    )
}

生命周期管理

使用 vef.Lifecycle 管理组件的启动和停止:

go
package subscribers

import (
    "context"
    "github.com/ilxqx/vef-framework-go/event"
    "github.com/ilxqx/vef-framework-go/vef"
)

type UserEventSubscriber struct {
    unsubscribe event.UnsubscribeFunc
}

func NewUserEventSubscriber(
    lc vef.Lifecycle,
    bus event.Bus,
) *UserEventSubscriber {
    subscriber := &UserEventSubscriber{}
    
    // Register startup hook
    lc.Append(vef.StartHook(func(ctx context.Context) error {
        // Subscribe to events on startup
        subscriber.unsubscribe = bus.Subscribe("user.created", 
            func(ctx context.Context, e event.Event) {
                // Handle event
            })
        return nil
    }))
    
    // Register shutdown hook
    lc.Append(vef.StopHook(func(ctx context.Context) error {
        // Unsubscribe on shutdown
        if subscriber.unsubscribe != nil {
            subscriber.unsubscribe()
        }
        return nil
    }))
    
    return subscriber
}

最佳实践

1. 依赖接口而非实现

go
// Good: Depend on interface
type UserService struct {
    repo UserRepository  // Interface
}

// Bad: Depend on concrete implementation
type UserService struct {
    repo *UserRepositoryImpl  // Concrete type
}

2. 保持构造函数简单

go
// Good: Simple constructor, just assign dependencies
func NewUserService(db orm.Db, logger log.Logger) *UserService {
    return &UserService{
        db:     db,
        logger: logger,
    }
}

// Bad: Complex logic in constructor
func NewUserService(db orm.Db) *UserService {
    // Don't do complex initialization here
    users, _ := db.NewSelect().Model(&User{}).Scan(context.Background())
    return &UserService{db: db, cachedUsers: users}
}

3. 使用模块组织依赖

go
// Good: Organize related dependencies in modules
func UserModule() vef.ModuleFunc {
    return vef.Module(
        vef.Provide(NewUserService),
        vef.Provide(NewUserRepository),
        vef.ProvideResource(NewUserResource),
    )
}

// Bad: Register all dependencies in main.go
func main() {
    vef.Run(
        vef.Provide(NewUserService),
        vef.Provide(NewOrderService),
        // ... many more
    )
}

4. 避免循环依赖

go
// Bad: Circular dependency
// UserService depends on OrderService
// OrderService depends on UserService

// Good: Extract shared logic to a third service
// UserService depends on SharedService
// OrderService depends on SharedService

下一步

基于 Apache License 2.0 许可发布