golang轻量级依赖注入容器插件库gocontainer的使用

Golang轻量级依赖注入容器插件库gocontainer的使用

关于gocontainer

gocontainer是一个轻量级的依赖注入(Dependency Injection)容器库,由Rafał Lorenz开发。它允许你在Go应用中轻松管理依赖关系。

基本使用示例

1. 从容器获取依赖并打印

package main

import (
    "github.com/vardius/gocontainer/example/repository"
    "github.com/vardius/gocontainer"
)

func main() {
    // 使用MustInvoke方法从容器获取repository.mysql并打印
    gocontainer.MustInvoke("repository.mysql", func(r Repository) {
        fmt.Println(r)
    })
}

2. 数据库服务注册

package database

import (
    "fmt"
    "database/sql"

    "github.com/vardius/gocontainer"
)

// NewDatabase 创建新的数据库连接
func NewDatabase() *sql.DB {
    db, _ := sql.Open("mysql", "dsn")
    return db
}

// init函数在包导入时自动执行,注册db服务
func init() {
    db := gocontainer.MustGet("db")
    gocontainer.Register("db", NewDatabase())
}

3. 仓库服务注册

package repository

import (
    "fmt"
    "database/sql"

    "github.com/vardius/gocontainer"
    _ "github.com/vardius/gocontainer/example/database" // 导入数据库包以触发init
)

type Repository interface {}

// NewRepository 创建新的仓库实例
func NewRepository(db *sql.DB) Repository {
    return &mysqlRepository{db}
}

type mysqlRepository struct {
    db *sql.DB
}

// init函数在包导入时自动执行,注册repository.mysql服务
func init() {
    db := gocontainer.MustGet("db")
    gocontainer.Register("repository.mysql", NewRepository(db.(*sql.DB)))
}

自定义容器实例

你可以禁用全局容器实例并创建自己的容器:

package main

import (
    "github.com/vardius/gocontainer/example/repository"
    "github.com/vardius/gocontainer"
)

func main() {
    // 禁用全局容器实例
    gocontainer.GlobalContainer = nil

    // 创建新的容器实例
    mycontainer := gocontainer.New()
    mycontainer.Register("test", 1)
}

主要方法

  • Register(name string, value interface{}): 注册服务到容器
  • MustGet(name string) interface{}: 从容器获取服务(如果不存在会panic)
  • MustInvoke(name string, fn interface{}): 安全调用容器中的服务
  • New(): 创建新的容器实例

gocontainer采用MIT许可证发布,是一个轻量级但功能完整的依赖注入解决方案,特别适合需要管理复杂依赖关系的Go应用程序。


更多关于golang轻量级依赖注入容器插件库gocontainer的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang轻量级依赖注入容器插件库gocontainer的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


GoContainer - Golang轻量级依赖注入容器

GoContainer是一个轻量级的依赖注入(DI)容器库,专为Go语言设计。它提供了简单易用的依赖注入功能,可以帮助开发者更好地管理应用程序中的组件依赖关系。

主要特性

  1. 轻量级设计,无额外依赖
  2. 支持构造函数注入和接口绑定
  3. 支持单例和瞬态(transient)生命周期
  4. 简单易用的API

安装

go get github.com/golobby/container/v3

基本用法

1. 简单绑定与解析

package main

import (
	"fmt"
	"github.com/golobby/container/v3"
)

type Database struct {
	ConnectionString string
}

func main() {
	// 绑定实例
	err := container.Singleton(func() Database {
		return Database{ConnectionString: "mysql://user:pass@localhost:3306/db"}
	})
	if err != nil {
		panic(err)
	}

	// 解析依赖
	var db Database
	err = container.Resolve(&db)
	if err != nil {
		panic(err)
	}

	fmt.Println(db.ConnectionString) // 输出: mysql://user:pass@localhost:3306/db
}

2. 接口绑定

package main

import (
	"fmt"
	"github.com/golobby/container/v3"
)

type Logger interface {
	Log(message string)
}

type ConsoleLogger struct{}

func (l ConsoleLogger) Log(message string) {
	fmt.Println(message)
}

func main() {
	// 绑定接口实现
	err := container.Singleton(func() Logger {
		return ConsoleLogger{}
	})
	if err != nil {
		panic(err)
	}

	// 解析依赖
	var logger Logger
	err = container.Resolve(&logger)
	if err != nil {
		panic(err)
	}

	logger.Log("Hello, Dependency Injection!") // 输出: Hello, Dependency Injection!
}

3. 构造函数注入

package main

import (
	"fmt"
	"github.com/golobby/container/v3"
)

type Service struct {
	Logger Logger
}

type Logger interface {
	Log(message string)
}

type ConsoleLogger struct{}

func (l ConsoleLogger) Log(message string) {
	fmt.Println(message)
}

func NewService(logger Logger) Service {
	return Service{Logger: logger}
}

func main() {
	// 绑定依赖
	err := container.Singleton(func() Logger {
		return ConsoleLogger{}
	})
	if err != nil {
		panic(err)
	}

	// 绑定服务,自动注入Logger
	err = container.Transient(func(logger Logger) Service {
		return NewService(logger)
	})
	if err != nil {
		panic(err)
	}

	// 解析服务
	var service Service
	err = container.Resolve(&service)
	if err != nil {
		panic(err)
	}

	service.Logger.Log("Service created with DI!") // 输出: Service created with DI!
}

4. 单例与瞬态生命周期

package main

import (
	"fmt"
	"github.com/golobby/container/v3"
)

type Counter struct {
	count int
}

func (c *Counter) Increment() {
	c.count++
	fmt.Printf("Count: %d\n", c.count)
}

func main() {
	// 单例模式 - 每次解析都是同一个实例
	err := container.Singleton(func() *Counter {
		return &Counter{}
	})
	if err != nil {
		panic(err)
	}

	// 瞬态模式 - 每次解析都是新实例
	err = container.Transient(func() Counter {
		return Counter{}
	})
	if err != nil {
		panic(err)
	}

	// 解析单例
	var singleton1, singleton2 *Counter
	_ = container.Resolve(&singleton1)
	_ = container.Resolve(&singleton2)
	
	singleton1.Increment() // Count: 1
	singleton2.Increment() // Count: 2 (同一个实例)

	// 解析瞬态
	var transient1, transient2 Counter
	_ = container.Resolve(&transient1)
	_ = container.Resolve(&transient2)
	
	transient1.Increment() // Count: 1
	transient2.Increment() // Count: 1 (不同实例)
}

高级用法

命名绑定

package main

import (
	"fmt"
	"github.com/golobby/container/v3"
)

func main() {
	// 命名绑定
	err := container.NamedSingleton("db1", func() string {
		return "Connection String 1"
	})
	if err != nil {
		panic(err)
	}

	err = container.NamedSingleton("db2", func() string {
		return "Connection String 2"
	})
	if err != nil {
		panic(err)
	}

	// 解析命名实例
	var connStr1, connStr2 string
	err = container.NamedResolve(&connStr1, "db1")
	if err != nil {
		panic(err)
	}
	err = container.NamedResolve(&connStr2, "db2")
	if err != nil {
		panic(err)
	}

	fmt.Println(connStr1) // 输出: Connection String 1
	fmt.Println(connStr2) // 输出: Connection String 2
}

条件绑定

package main

import (
	"fmt"
	"github.com/golobby/container/v3"
)

type Config struct {
	Env string
}

type Service struct {
	Config Config
}

func NewService(config Config) Service {
	return Service{Config: config}
}

func main() {
	// 模拟环境配置
	config := Config{Env: "production"}

	// 绑定配置
	err := container.Instance(config)
	if err != nil {
		panic(err)
	}

	// 绑定服务
	err = container.Transient(func(c Config) Service {
		return NewService(c)
	})
	if err != nil {
		panic(err)
	}

	// 解析服务
	var service Service
	err = container.Resolve(&service)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Service running in %s environment\n", service.Config.Env)
}

最佳实践

  1. 在应用启动时注册所有依赖:通常在main函数或初始化代码中完成所有绑定
  2. 优先使用接口:这使得代码更易于测试和维护
  3. 合理使用生命周期
    • 单例(Singleton):适用于无状态服务、配置、数据库连接等
    • 瞬态(Transient):适用于有状态服务,每次需要新实例的情况
  4. 避免服务定位器模式:尽量使用构造函数注入,而不是在代码中直接解析依赖

总结

GoContainer是一个简单而强大的依赖注入容器,它可以帮助你更好地组织Go应用程序的依赖关系。通过使用依赖注入,你的代码将变得更加模块化、可测试和可维护。虽然它没有一些更复杂的DI框架(如Dig或Wire)的所有功能,但对于大多数中小型项目来说,它提供了足够的功能且保持了简单性。

对于更复杂的场景,你可能需要考虑其他DI框架,但对于大多数用例,GoContainer提供了一个很好的平衡点,既足够强大又保持简单易用。

回到顶部