dix

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

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

Go to latest
Published: Jun 7, 2025 License: MIT Imports: 4 Imported by: 15

README

Go Doc Build Status Go Report Card

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

🎯 核心设计理念

Dix 采用统一的 Inject 方法设计,通过单一接口支持多种依赖注入模式:

  • 函数注入 - 解析函数参数并调用
  • 结构体注入 - 注入到结构体字段
  • 方法注入 - 自动调用 DixInject 前缀方法
  • 获取依赖实例 - 通过函数参数获取依赖实例

设计优势: Inject 方法的入参可以是函数、指针、接口、map、list 等,一个方法涵盖所有依赖注入需求,提供更加统一和灵活的 API。

🚀 快速开始

安装
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}
    })
    
    // 方式1: 结构体注入
    var service UserService
    dix.Inject(container, &service)
    service.Logger.Log("Hello, Dix!")
    
    // 方式2: 函数注入
    dix.Inject(container, func(service *UserService) {
        service.Logger.Log("Hello from function injection!")
    })
    
    // 方式3: 获取依赖实例的用法
    var logger Logger
    var userService *UserService
    dix.Inject(container, func(l Logger, us *UserService) {
        logger = l
        userService = us
    })
    logger.Log("Hello from unified 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}
    })
    
    // 统一的注入方式
    dixglobal.Inject(func(service *UserService) {
        service.Logger.Log("Hello from global container!")
    })
    
    // 获取依赖实例的用法
    var service *UserService
    dixglobal.Inject(func(s *UserService) {
        service = s
    })
    service.Logger.Log("Got service via injection!")
}

📚 文档

核心文档
示例代码

🎯 核心概念

容器 (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. 函数注入(推荐)
// 直接使用依赖
dix.Inject(container, func(db Database, logger Logger) {
    // 使用注入的依赖
    logger.Log("Database connected")
})

// 获取依赖实例的用法
var logger Logger
var service *UserService
dix.Inject(container, func(l Logger, s *UserService) {
    logger = l    // 获取 Logger 实例
    service = s   // 获取 UserService 实例
})
2. 结构体注入
type Handler struct {
    DB     Database `dix:""`
    Logger Logger   `dix:""`
}

var handler Handler
dix.Inject(container, &handler)
3. 方法注入
type Service struct {
    logger Logger
    db     Database
}

// DixInject 前缀的方法会被自动调用
func (s *Service) DixInjectLogger(logger Logger) {
    s.logger = logger
}

func (s *Service) DixInjectDatabase(db Database) {
    s.db = db
}

var service Service
dix.Inject(container, &service)

🔧 高级特性

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

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

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

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

📋 API 对比

统一设计的优势
传统方式 Dix 统一方式
container.Get(&target) dix.Inject(container, func(t Target) { target = t })
container.Inject(target) dix.Inject(container, target)
container.Call(fn) dix.Inject(container, fn)

统一的 Inject 方法支持:

  • ✅ 函数:func(deps...) { ... }
  • ✅ 结构体指针:&struct{}
  • ✅ 接口类型:interface{}
  • ✅ 切片类型:[]T
  • ✅ 映射类型:map[string]T

🌟 特性亮点

  • 🎯 统一 API: 一个 Inject 方法处理所有依赖注入场景
  • 🔒 类型安全: 编译时类型检查,运行时错误详细
  • ⚡ 高性能: 优化的依赖解析和缓存机制
  • 🔍 循环检测: 自动检测和报告循环依赖
  • 📊 可视化: 依赖关系图生成和分析
  • 🧩 模块化: 清晰的架构分层和组件解耦
  • 🛡️ 错误友好: 详细的错误信息和调试支持

💡 设计思路

Dix 的核心设计理念是简化和统一

  1. 统一接口: Inject 方法可以处理所有类型的依赖注入需求
  2. 类型灵活: 支持函数、指针、接口、集合等多种类型
  3. 功能全面: 既能注入依赖,也能获取实例,满足所有需求
  4. 使用简单: 学习成本低,API 直观易懂

这种设计让开发者只需要掌握一个方法,就能处理所有的依赖注入场景,大大简化了框架的使用复杂度。

🤝 贡献

欢迎提交 Issue 和 Pull Request!

�� 许可证

MIT License

Documentation

Index

Constants

View Source
const (
	InjectMethodPrefix = dixinternal.InjectMethodPrefix
)

Variables

This section is empty.

Functions

func Inject added in v0.1.27

func Inject[T any](container Container, target T, opts ...Option) (result T, err error)

Inject 统一的依赖注入方法

这是框架的核心方法,按照最原始的设计,只支持函数和结构体类型。 提供了统一的依赖注入接口,简化API设计。

支持的输入类型:

  • 函数:func(deps...) - 解析函数参数并调用函数
  • 结构体指针:&struct{} - 注入到结构体字段

函数注入规则:

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

结构体注入规则:

  • 字段必须是导出的(首字母大写)
  • 支持嵌套结构体注入
  • 支持方法注入(DixInject前缀的方法)

获取实例的用法:

  • 通过函数参数获取:var logger Logger; Inject(container, func(l Logger) { logger = l })
  • 直接在函数中使用:Inject(container, func(l Logger) { l.Log("message") })
  • 批量获取:var logger Logger; var db *Database; Inject(container, func(l Logger, d *Database) { logger, db = l, d })

错误处理:

  • 参数解析失败时返回详细错误信息
  • 函数调用 panic 会被捕获并转换为错误
  • 循环依赖会被检测并报错

示例:

// 函数注入
_, err := dix.Inject(container, func(logger Logger, db *Database, handlers []Handler) {
    // 使用注入的依赖启动服务器
    startServer(logger, db, handlers)
})
if err != nil {
    log.Fatal(err)
}

// 结构体注入
type Service struct {
    Logger Logger
    DB     *Database
}
service, err := dix.Inject(container, &Service{})
if err != nil {
    log.Fatal(err)
}

// 获取单个依赖实例
var logger Logger
_, err := dix.Inject(container, func(l Logger) {
    logger = l
})
if err != nil {
    log.Fatal(err)
}

// 批量获取多个依赖实例
var logger Logger
var db *Database
var handlers []Handler
_, err := dix.Inject(container, func(l Logger, d *Database, h []Handler) {
    logger, db, handlers = l, d, h
})
if err != nil {
    log.Fatal(err)
}

// 方法注入示例
type UserService struct {
    logger Logger
    db     *Database
}
func (s *UserService) DixInjectLogger(logger Logger) { s.logger = logger }
func (s *UserService) DixInjectDatabase(db *Database) { s.db = db }

service, err := dix.Inject(container, &UserService{})
if err != nil {
    log.Fatal(err)
}

参数:

  • container: 依赖注入容器
  • target: 注入目标(函数或结构体指针)
  • opts: 注入选项(可选)

返回值:

  • T: 如果target是函数,返回零值(nil);如果是结构体,返回注入后的结构体
  • error: 注入失败时的错误信息

func InjectMust

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

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, errors.Wrap(err, "failed to load config")
    }
    return config, nil
})

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

参数:

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

Types

type Container

type Container = dixinternal.Container

func New

func New(opts ...Option) Container

New 创建新的依赖注入容器

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