依赖注入
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