Skip to content

Go-Inject 是一个基于 Facebook 的 [inject](https://github.com/facebookarchive/inject) 项目增强的 Go 语言依赖注入框架

License

ComingCL/go-inject

Repository files navigation

Go-Inject - Enhanced Dependency Injection Framework

Go Version License Tests

Go-Inject 是一个基于 Facebook 的 inject 项目增强的 Go 语言依赖注入框架。它提供了基于反射的依赖注入功能,并在原有基础上增加了深度注入等重要特性。

🚀 主要特性

原有特性(继承自 Facebook inject)

  • 基于反射的依赖注入:自动解析和注入依赖关系
  • 结构体标签支持:使用 inject:"" 标签标记需要注入的字段
  • 命名注入:支持通过名称注入特定实例
  • 私有注入:支持创建私有实例
  • 接口注入:自动匹配实现了接口的类型
  • 内联结构体:支持内联结构体的依赖注入
  • 循环依赖检测:自动检测并报告循环依赖
  • 日志支持:可配置的注入过程日志记录

🆕 增强特性

  • 🎯 深度注入(Deep Injection):自动注入手动创建对象的内部依赖
  • 🔄 递归依赖解析:支持多层嵌套的依赖关系自动解析
  • 🛡️ 增强的错误处理:更详细的错误信息和调试支持
  • 📊 完善的测试覆盖:包含深度注入的完整测试用例

📦 安装

go get github.com/ComingCL/go-inject

🎯 深度注入特性详解

什么是深度注入?

深度注入是本项目相对于原始 Facebook inject 的主要增强功能。它解决了以下场景:

场景描述:当你手动创建了一个对象,该对象内部包含其他需要依赖注入的字段时,传统的依赖注入框架无法处理这种情况。

// 传统方式:无法自动注入 d.A 内部的依赖
d := &Service{
    A: &ComponentA{}, // 手动创建的对象,内部的 C 字段无法被自动注入
}

深度注入解决方案:自动检测并注入手动创建对象的内部依赖。

深度注入工作原理

  1. 自动发现:框架检测到字段中存在手动创建的对象
  2. 自动注册:将发现的对象自动注册到依赖图中
  3. 递归注入:递归地为该对象的所有依赖字段进行注入
  4. 多层支持:支持任意深度的嵌套依赖关系

📚 使用指南

基本用法

package main

import (
    "fmt"
    "github.com/ComingCL/go-inject"
)

// 定义服务接口
type Logger interface {
    Log(message string)
}

// 实现日志服务
type ConsoleLogger struct{}

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

// 定义数据库服务
type Database struct {
    Logger Logger `inject:""`
}

func (d *Database) Query(sql string) {
    d.Logger.Log("Executing: " + sql)
}

// 定义用户服务
type UserService struct {
    DB     *Database `inject:""`
    Logger Logger    `inject:""`
}

func (u *UserService) GetUser(id int) {
    u.Logger.Log(fmt.Sprintf("Getting user %d", id))
    u.DB.Query("SELECT * FROM users WHERE id = ?")
}

func main() {
    var g inject.Graph
    
    // 注册依赖
    logger := &ConsoleLogger{}
    db := &Database{}
    userService := &UserService{}
    
    g.Provide(&inject.Object{Value: logger})
    g.Provide(&inject.Object{Value: db})
    g.Provide(&inject.Object{Value: userService})
    
    // 执行依赖注入
    if err := g.Populate(); err != nil {
        panic(err)
    }
    
    // 使用服务
    userService.GetUser(123)
}

深度注入示例

package main

import (
    "fmt"
    "github.com/ComingCL/go-inject"
)

type ComponentA struct {
    C *ComponentC `inject:""`
}

type ComponentB struct{}

type ComponentC struct {
    B *ComponentB `inject:""`
}

type Service struct {
    A *ComponentA `inject:""`
}

func main() {
    var g inject.Graph
    
    // 注册基础依赖
    b := &ComponentB{}
    c := &ComponentC{}
    
    // 创建包含手动实例的服务
    service := &Service{
        A: &ComponentA{}, // 手动创建的实例
    }
    
    g.Provide(&inject.Object{Value: b})
    g.Provide(&inject.Object{Value: c})
    g.Provide(&inject.Object{Value: service})
    
    // 执行依赖注入(包括深度注入)
    if err := g.Populate(); err != nil {
        panic(err)
    }
    
    // 验证深度注入结果
    fmt.Printf("service.A.C != nil: %v\n", service.A.C != nil)         // true
    fmt.Printf("service.A.C.B != nil: %v\n", service.A.C.B != nil)     // true
    fmt.Printf("service.A.C.B == b: %v\n", service.A.C.B == b)         // true
}

命名注入

type Config struct {
    DatabaseURL string
    RedisURL    string
}

type Service struct {
    MainDB  *Database `inject:"main_db"`
    CacheDB *Database `inject:"cache_db"`
}

func main() {
    var g inject.Graph
    
    mainDB := &Database{URL: "postgres://main"}
    cacheDB := &Database{URL: "redis://cache"}
    service := &Service{}
    
    g.Provide(&inject.Object{Value: mainDB, Name: "main_db"})
    g.Provide(&inject.Object{Value: cacheDB, Name: "cache_db"})
    g.Provide(&inject.Object{Value: service})
    
    g.Populate()
}

私有注入

type Service struct {
    Logger Logger `inject:"private"`  // 创建私有实例
}

🏗️ 项目结构

go-inject/
├── README.md              # 项目文档
├── LICENSE               # MIT 许可证
├── go.mod               # Go 模块文件
├── inject.go            # 核心注入逻辑
├── inject_test.go       # 测试用例
├── structtag.go         # 结构体标签解析
├── structtag_test.go    # 标签解析测试
├── ioc_container.go     # IoC 容器实现
└── examples/            # 使用示例
    ├── basic/           # 基础用法示例
    ├── deep-injection/  # 深度注入示例
    ├── web-service/     # Web 服务示例
    └── advanced/        # 高级用法示例

🧪 测试

运行所有测试:

go test -v

运行特定测试:

go test -run TestForDeepInject -v

查看测试覆盖率:

go test -cover

📈 性能对比

特性 Facebook inject Go-Inject
基础注入
深度注入
递归依赖 部分支持 ✅ 完全支持
错误处理 基础 增强
测试覆盖 基础 完整

🔄 从 Facebook inject 迁移

如果你正在使用 Facebook 的 inject 包,迁移到 go-inject 非常简单:

  1. 更新导入路径:
// 旧的
import "github.com/facebookgo/inject"

// 新的
import "github.com/ComingCL/go-inject"
  1. 代码无需修改,所有原有功能保持兼容

  2. 可选:利用新的深度注入特性优化你的代码

🤝 贡献指南

我们欢迎社区贡献!请遵循以下步骤:

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/amazing-feature)
  3. 提交更改 (git commit -m 'Add some amazing feature')
  4. 推送到分支 (git push origin feature/amazing-feature)
  5. 开启 Pull Request

开发环境设置

# 克隆仓库
git clone https://github.com/ComingCL/go-inject.git
cd go-inject

# 运行测试
go test -v

# 检查代码格式
go fmt ./...

# 运行静态分析
go vet ./...

📄 许可证

本项目基于 MIT 许可证开源。详见 LICENSE 文件。

🙏 致谢

  • 感谢 Facebook 团队开源的原始 inject 项目
  • 感谢所有为本项目做出贡献的开发者

📞 支持

如果你遇到问题或有建议,请:

  1. 查看 examples 目录中的示例
  2. 搜索现有的 Issues
  3. 创建新的 Issue 描述你的问题

🔗 相关链接


Go-Inject - 让依赖注入更简单、更强大! 🚀

About

Go-Inject 是一个基于 Facebook 的 [inject](https://github.com/facebookarchive/inject) 项目增强的 Go 语言依赖注入框架

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages