dix

package module
v0.3.21-alpha.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2025 License: MIT Imports: 2 Imported by: 15

README

Dix - 现代化 Go 依赖注入框架

Go Version License Go Report Card Coverage Status

Dix 是一个现代化的 Go 依赖注入框架,采用模块化架构设计,提供类型安全的泛型 API 和高性能的依赖管理能力。

✨ 特性

🚀 现代化设计
  • 泛型支持:完全的 Go 1.18+ 泛型 API,编译时类型安全
  • 模块化架构:清晰的分层设计,易于扩展和维护
  • 零反射:高性能实现,避免运行时反射开销
  • 函数式 API:简洁直观的函数式接口设计
🔧 强大功能
  • 循环依赖检测:智能检测和报告循环依赖问题
  • 多种注入方式:支持构造函数、结构体字段、方法注入
  • 灵活提供者:支持函数、值、接口等多种提供者类型
  • 命名空间隔离:支持多容器实例,避免全局状态污染
📊 高性能
  • 预编译优化:依赖图预编译,运行时零开销
  • 内存池化:智能内存管理,减少 GC 压力
  • 并发安全:线程安全的容器操作
  • 懒加载:按需实例化,优化启动性能

🚀 快速开始

安装
go get github.com/pubgo/dix
基础用法
package main

import (
    "fmt"
    "github.com/pubgo/dix"
)

// 定义接口和实现
type Logger interface {
    Log(msg string)
}

type ConsoleLogger struct{}

func (c *ConsoleLogger) Log(msg string) {
    fmt.Println("LOG:", msg)
}

type UserService struct {
    Logger Logger
}

func main() {
    // 创建容器
    container := dix.New()
    
    // 注册提供者
    dix.Provide(container, func() Logger {
        return &ConsoleLogger{}
    })
    
    dix.Provide(container, func(logger Logger) *UserService {
        return &UserService{Logger: logger}
    })
    
    // 获取实例(泛型 API)
    service := dix.MustGet[*UserService](container)
    service.Logger.Log("Hello, Dix!")
    
    // 或者使用依赖注入
    var injectedService UserService
    dix.Inject(container, &injectedService)
    injectedService.Logger.Log("Hello from injection!")
}
全局容器用法
package main

import (
    "github.com/pubgo/dix/dixglobal"
)

func main() {
    // 使用全局容器,更简洁
    dixglobal.Provide(func() Logger {
        return &ConsoleLogger{}
    })
    
    dixglobal.Provide(func(logger Logger) *UserService {
        return &UserService{Logger: logger}
    })
    
    // 直接获取实例
    service := dixglobal.Get[*UserService]()
    service.Logger.Log("Hello from global container!")
}

📚 文档

核心文档
示例代码

🎯 核心概念

容器 (Container)

容器是依赖管理的核心,负责存储提供者和解析依赖关系:

// 创建新容器
container := dix.New()

// 或使用全局容器
dixglobal.Provide(provider)
提供者 (Provider)

提供者定义如何创建和配置依赖项:

// 函数提供者
dix.Provide(container, func() Database {
    return &PostgresDB{Host: "localhost"}
})

// 带依赖的提供者
dix.Provide(container, func(db Database, logger Logger) *UserService {
    return &UserService{DB: db, Logger: logger}
})

// 值提供者
dix.Provide(container, &Config{Port: 8080})
注入方式
1. 泛型获取(推荐)
// 类型安全的实例获取
logger := dix.MustGet[Logger](container)
service, err := dix.Get[*UserService](container)
2. 结构体注入
type Handler struct {
    DB     Database `dix:""`
    Logger Logger   `dix:""`
}

var handler Handler
dix.Inject(container, &handler)
3. 函数注入
dix.Inject(container, func(db Database, logger Logger) {
    // 使用注入的依赖
    logger.Log("Database connected")
})

🔧 高级特性

循环依赖检测
// Dix 会自动检测循环依赖
dix.Provide(container, func(b B) A { return A{} })
dix.Provide(container, func(a A) B { return B{} })

// 获取时会报告循环依赖错误
_, err := dix.Get[A](container)
// err: circular dependency detected: A -> B -> A
集合注入
// 注册多个相同类型的提供者
dix.Provide(container, func() Handler { return &HTTPHandler{} })
dix.Provide(container, func() Handler { return &GRPCHandler{} })

// 获取所有实例
handlers := dix.MustGet[[]Handler](container)
fmt.Printf("Registered %d handlers\n", len(handlers))
映射注入
// 命名提供者
dix.Provide(container, func() Handler { return &HTTPHandler{} })
dix.Provide(container, func() Handler { return &GRPCHandler{} })

// 获取映射
handlerMap := dix.MustGet[map[string]Handler](container)
for name, handler := range handlerMap {
    fmt.Printf("Handler %s: %T\n", name, handler)
}
依赖图可视化
// 查看依赖关系图
graph := dix.GetGraph(container)
fmt.Printf("Providers: %s\n", graph.Providers)
fmt.Printf("Objects: %s\n", graph.Objects)

🏗️ 架构层次

Dix 采用分层架构设计:

┌─────────────────────────────────────┐
│           Public API                │  ← dix 包:用户友好的 API
├─────────────────────────────────────┤
│         Global Container            │  ← dixglobal 包:全局容器
├─────────────────────────────────────┤
│        Internal Core                │  ← dixinternal 包:核心实现
└─────────────────────────────────────┘
API 层次选择
  • 简单应用:使用 dixglobal 包的全局容器
  • 复杂应用:使用 dix 包的容器实例
  • 库开发:使用 dixinternal 包的底层 API

🚀 性能优势

v2.0 vs v1.x 性能对比
指标 v1.x v2.0 改进
代码行数 1,200+ 373 -69%
内存使用 基准 -30% 更少内存分配
启动时间 基准 -40% 预编译优化
运行时性能 基准 +25% 零反射实现
优化特性
  • 预编译依赖图:启动时构建,运行时零开销
  • 类型缓存:避免重复类型解析
  • 内存池化:减少 GC 压力
  • 并发优化:线程安全的高效实现

🔄 迁移指南

从 v1.x 迁移到 v2.0?查看我们的详细迁移指南

主要 API 变化
v1.x v2.0
dix.NewDix() dix.New()
container.Provide(fn) dix.Provide(container, fn)
container.Inject(target) dix.Inject(container, target)
container.Get(&target) dix.Get[T](container)

🤝 贡献

我们欢迎社区贡献!请查看 CONTRIBUTING.md 了解如何参与项目开发。

开发环境
# 克隆项目
git clone https://github.com/pubgo/dix.git
cd dix

# 安装依赖
go mod tidy

# 运行测试
go test ./...

# 运行示例
go run example/basic/main.go

📄 许可证

本项目采用 Apache 2.0 许可证

🙏 致谢

  • 设计灵感来源于 uber-go/dig
  • 感谢所有贡献者的支持和反馈

Dix - 让依赖注入变得简单而强大 🚀

Documentation

Index

Constants

View Source
const (
	InjectMethodPrefix = dixinternal.InjectMethodPrefix
)

Variables

This section is empty.

Functions

func Get

func Get[T any](container Container, opts ...Option) (T, error)

Get 获取指定类型的实例(泛型版本)

支持获取的类型:

  • 单个实例:T(直接指定类型)
  • 切片:[]T(获取所有 T 类型的实例)
  • 映射:map[string]T(获取带名称的 T 类型实例)

类型解析规则:

  • 接口类型会匹配所有实现该接口的类型
  • 结构体类型精确匹配
  • 指针类型匹配对应的指针实例

错误情况:

  • 类型未注册:返回 ErrTypeNotFound
  • 循环依赖:返回 ErrCircularDependency
  • 提供者调用失败:返回包装后的错误

示例:

// 获取单个实例
logger, err := dix.Get[Logger](container)
if err != nil {
    log.Fatal(err)
}

// 获取切片
handlers, err := dix.Get[[]Handler](container)
if err != nil {
    log.Fatal(err)
}

// 获取映射
databases, err := dix.Get[map[string]Database](container)
if err != nil {
    log.Fatal(err)
}

参数:

  • container: 依赖注入容器
  • opts: 可选配置

返回值:

  • T: 请求的实例
  • error: 获取失败时的错误信息

func Inject added in v0.1.27

func Inject(container Container, fn interface{}, opts ...Option) error

Inject 注入函数

解析函数参数并调用函数。 通常用于启动函数或回调函数的依赖注入。

参数:

  • container: 依赖注入容器
  • fn: 目标函数,必须是函数类型
  • opts: 注入选项(可选)

函数注入规则:

  • 函数只能有入参,不能有出参
  • 函数参数类型必须在容器中已注册
  • 支持的参数类型:
  • 指针类型:*T
  • 接口类型:interface{}
  • 结构体类型:struct{}
  • 切片类型:[]T(注入所有匹配的实例)
  • 映射类型:map[string]T(注入带名称的实例)
  • 不支持基本类型参数:string, int, bool 等
  • 支持可变参数:func(handlers ...Handler)

函数限制:

  • 函数不能有返回值(包括 error)
  • 函数参数不能是基本类型

错误处理:

  • 参数解析失败时返回详细错误信息
  • 函数调用 panic 会被捕获并转换为错误
  • 如果函数有返回值,注册时会被拒绝

示例:

// 有效的启动函数
func StartServer(logger Logger, db *Database, handlers []Handler) {
    // 使用注入的依赖启动服务器
}

// 有效的回调函数
func ProcessRequest(ctx Context, service *UserService) {
    // 处理请求
}

// 无效的函数(有返回值)
func InvalidFunc(logger Logger) error {
    return nil // 不允许有返回值
}

// 无效的函数(基本类型参数)
func InvalidFunc2(name string, port int) {
    // 不允许基本类型参数
}

// 使用示例
container := dix.New()
container.Provide(NewLogger)
container.Provide(NewDatabase)
container.Provide(NewUserService)

// 注入并调用启动函数
err := dix.Inject(container, StartServer)
if err != nil {
    log.Fatal(err)
}

func MustGet

func MustGet[T any](container Container, opts ...Option) T

MustGet 获取指定类型的实例,失败时panic(泛型版本)

功能与 Get 相同,但在获取失败时会 panic 而不是返回错误。 适用于确信实例一定存在的场景,如应用启动阶段。

支持获取的类型:

  • 单个实例:T(直接指定类型)
  • 切片:[]T(获取所有 T 类型的实例)
  • 映射:map[string]T(获取带名称的 T 类型实例)

使用场景:

  • 应用启动阶段,确信依赖已正确注册
  • 测试代码中,简化错误处理
  • 配置阶段,依赖缺失应该立即失败

示例:

// 获取单个实例(确信存在)
logger := dix.MustGet[Logger](container)

// 获取切片(可能为空)
handlers := dix.MustGet[[]Handler](container)

// 在应用启动中使用
func main() {
    container := setupContainer()

    // 这些依赖必须存在,否则应用无法启动
    logger := dix.MustGet[Logger](container)
    db := dix.MustGet[*Database](container)

    startServer(logger, db)
}

参数:

  • container: 依赖注入容器
  • opts: 可选配置

返回值:

  • T: 请求的实例

注意:失败时会 panic,请确保在适当的场景下使用

func Provide added in v0.3.1

func Provide(container Container, provider any)

Provide 注册依赖提供者

支持的提供者函数签名:

  • func() T - 简单提供者
  • func() (T, error) - 带错误处理的提供者
  • func(dep1 D1, dep2 D2) T - 带依赖的提供者
  • func(dep1 D1, dep2 D2) (T, error) - 带依赖和错误处理的提供者

支持的输出类型:

  • 指针类型:*T
  • 接口类型:interface{}
  • 结构体类型:struct{}
  • Map类型:map[K]V
  • Slice类型:[]T
  • 函数类型:func(...)

不支持的类型:

  • 基本类型:string, int, bool 等(请使用指针类型替代)

错误处理:

  • 当提供者函数返回 (T, error) 时,如果 error 不为 nil,提供者调用失败
  • 错误会被包装并包含提供者类型和位置信息
  • 提供者注册失败时会 panic(使用 assert.Must)

示例:

// 简单提供者
dix.Provide(container, func() *Database {
    return &Database{Host: "localhost"}
})

// 带错误处理的提供者
dix.Provide(container, func() (*Config, error) {
    config, err := loadConfig()
    if err != nil {
        return nil, fmt.Errorf("failed to load config: %w", err)
    }
    return config, nil
})

// 带依赖的提供者
dix.Provide(container, func(config *Config) (*Database, error) {
    db, err := sql.Open("postgres", config.DatabaseURL)
    if err != nil {
        return nil, fmt.Errorf("failed to connect: %w", err)
    }
    return &Database{DB: db}, nil
})

参数:

  • container: 依赖注入容器
  • provider: 提供者函数

Types

type Container

type Container = dixinternal.Container

func New

func New(opts ...Option) Container

New 创建新的依赖注入容器

type Dix

type Dix = Container

为了向后兼容,保留旧的类型别名 Deprecated: 使用 Container 替代

type Graph

type Graph = dixinternal.Graph

func GetGraph

func GetGraph(container Container) *Graph

GetGraph 获取依赖关系图

container: 依赖注入容器

type Option

type Option = dixinternal.Option

func WithValuesNull added in v0.3.9

func WithValuesNull() Option

WithValuesNull 配置选项:允许值为null

type Options added in v0.0.9

type Options = dixinternal.Options

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL