golang自定义依赖注入容器插件kinit的使用

Golang自定义依赖注入容器插件kinit的使用

KInit简介

KInit是一个Go语言的依赖注入容器库,提供全局IoC容器实现自动依赖注入功能。

安装

go get github.com/go-kata/kinit

当前状态

这是一个beta版本,API尚未稳定。

版本说明

在第一个主要版本发布前,次版本号(v0.x.0)应被视为主要版本,补丁版本(v0.0.x)应被视为次版本。

基本使用

获取容器

获取全局容器:

kinit.Global()

创建本地容器:

ctr := kinit.NewContainer()

构造器(Constructors)

构造器用于创建对象(依赖项),接口定义如下:

type Constructor interface {
    Type() reflect.Type
    Parameters() []reflect.Type
    Create(a ...reflect.Value) (reflect.Value, kdone.Destructor, error)
}

注册构造器:

kinitx.MustProvide(func(config *Config) (*Object, kdone.Destructor, error) { ... })

处理器(Processors)

处理器用于处理已创建的对象,接口定义如下:

type Processor interface {
    Type() reflect.Type
    Parameters() []reflect.Type
    Process(obj reflect.Value, a ...reflect.Value) error
}

注册处理器:

kinitx.MustAttach((*Object).SetOptionalProperty)

函子(Functors)

函子表示要在容器中运行的函数,接口定义如下:

type Functor interface {
    Parameters() []reflect.Type
    Call(a ...reflect.Value) ([]Functor, error)
}

运行函子:

kinitx.MustRun(func(app *Application) error { ... })

KInitX扩展包

KInitX提供了主要接口的默认实现和其他便捷工具。

构造器实现

// 基于函数的构造器
kinitx.MustProvide(func(config *Config) (*Object, kdone.Destructor, error) { ... })

// 基于io.Closer的构造器
kinitx.MustProvide(func(logger *log.Logger) (*sql.DB, error) { ... })

// 结构体成员初始化器
kinitx.MustProvide((*Config)(nil))

绑定器

kinitx.MustBind((*StorageInterface)(nil), (*PostgresStrorage)(nil))

完整示例

package main

import (
    "github.com/go-kata/kinit/kinitx"
    "log"
    "database/sql"
)

// Config 配置结构体
type Config struct {
    DSN string
}

// Service 服务接口
type Service interface {
    DoSomething()
}

// RealService 服务实现
type RealService struct{}

func (s *RealService) DoSomething() {
    log.Println("Doing something...")
}

func main() {
    // 注册构造器
    kinitx.MustProvide(func() *Config {
        return &Config{DSN: "user:password@/dbname"}
    })
    
    kinitx.MustProvide(func(config *Config) (*sql.DB, error) {
        return sql.Open("mysql", config.DSN)
    })
    
    kinitx.MustProvide(func() *RealService {
        return &RealService{}
    })
    
    // 绑定接口
    kinitx.MustBind((*Service)(nil), (*RealService)(nil))
    
    // 运行主函数
    kinitx.MustRun(func(svc Service, db *sql.DB) error {
        svc.DoSomething()
        // 使用db...
        return nil
    })
}

依赖图验证(KInitQ)

添加检查代码:

main.go:

// +build !inspect

package main

import "github.com/go-kata/kinit/kinitx"

func main() { kinitx.MustRun(EntryPoint) }

main_inspect.go:

// +build inspect

package main

import "github.com/go-kata/kinit/kinitx"

func main() { kinitx.MustInspect(nil) }

运行检查:

go run -tags inspect

相关项目


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

1 回复

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


Golang 自定义依赖注入容器插件 Kinit 使用指南

Kinit 是一个轻量级的 Golang 依赖注入容器,它可以帮助你管理应用程序中的依赖关系,实现松耦合的设计。下面我将详细介绍如何使用 Kinit。

基本概念

Kinit 的核心概念包括:

  • Provider - 提供依赖项的创建逻辑
  • Constructor - 实际创建依赖项的函数
  • Container - 管理依赖项的生命周期和注入

安装

go get github.com/go-kata/kinit

基础用法

1. 创建容器

package main

import (
	"fmt"
	"github.com/go-kata/kinit"
)

type Database struct {
	ConnString string
}

type Logger struct {
	Level string
}

func main() {
	// 创建容器
	ctr := kinit.NewContainer()
	
	// 注册提供者
	ctr.MustProvide(func() *Database {
		return &Database{ConnString: "user:pass@localhost:5432/db"}
	})
	
	ctr.MustProvide(func() *Logger {
		return &Logger{Level: "debug"}
	})
	
	// 使用依赖
	err := ctr.Invoke(func(db *Database, logger *Logger) {
		fmt.Printf("Database: %+v\n", db)
		fmt.Printf("Logger: %+v\n", logger)
	})
	
	if err != nil {
		panic(err)
	}
}

2. 带参数的构造函数

func NewDatabase(config *Config) *Database {
	return &Database{ConnString: config.DBConnString}
}

func NewLogger(config *Config) *Logger {
	return &Logger{Level: config.LogLevel}
}

type Config struct {
	DBConnString string
	LogLevel     string
}

func main() {
	ctr := kinit.NewContainer()
	
	// 先注册配置
	ctr.MustProvide(func() *Config {
		return &Config{
			DBConnString: "user:pass@localhost:5432/db",
			LogLevel:     "info",
		}
	})
	
	// 注册依赖
	ctr.MustProvide(NewDatabase)
	ctr.MustProvide(NewLogger)
	
	// 使用
	err := ctr.Invoke(func(db *Database, logger *Logger) {
		fmt.Printf("Database: %s\n", db.ConnString)
		fmt.Printf("Logger level: %s\n", logger.Level)
	})
	
	if err != nil {
		panic(err)
	}
}

高级特性

1. 接口绑定

type UserRepository interface {
	FindByID(id int) string
}

type userRepoImpl struct{}

func (r *userRepoImpl) FindByID(id int) string {
	return fmt.Sprintf("User%d", id)
}

func NewUserRepo() UserRepository {
	return &userRepoImpl{}
}

func main() {
	ctr := kinit.NewContainer()
	ctr.MustProvide(NewUserRepo)
	
	err := ctr.Invoke(func(repo UserRepository) {
		fmt.Println(repo.FindByID(1)) // 输出: User1
	})
	
	if err != nil {
		panic(err)
	}
}

2. 生命周期管理

func main() {
	ctr := kinit.NewContainer()
	
	// 单例模式
	ctr.MustProvide(func() *Database {
		fmt.Println("Creating database connection")
		return &Database{ConnString: "singleton_conn"}
	}, kinit.Singleton())
	
	// 每次调用都新建实例
	ctr.MustProvide(func() *Logger {
		fmt.Println("Creating new logger instance")
		return &Logger{Level: "debug"}
	})
	
	// 第一次调用
	_ = ctr.Invoke(func(db *Database, logger *Logger) {
		fmt.Printf("DB: %p, Logger: %p\n", db, logger)
	})
	
	// 第二次调用
	_ = ctr.Invoke(func(db *Database, logger *Logger) {
		fmt.Printf("DB: %p, Logger: %p\n", db, logger)
	})
	
	// 输出:
	// Creating database connection
	// Creating new logger instance
	// DB: 0xc000010030, Logger: 0xc000010038
	// Creating new logger instance
	// DB: 0xc000010030, Logger: 0xc000010040
}

3. 可选依赖

func main() {
	ctr := kinit.NewContainer()
	
	// 注册可选依赖
	ctr.MustProvide(func() (*Logger, error) {
		return &Logger{Level: "debug"}, nil
	})
	
	// 使用可选依赖
	err := ctr.Invoke(func(logger *Logger) {
		fmt.Println("Logger is present")
	})
	
	if err != nil {
		fmt.Println("Logger is missing")
	}
}

最佳实践

  1. 分层注册:按照模块分层注册依赖
  2. 接口编程:尽量依赖接口而非具体实现
  3. 错误处理:构造函数可以返回错误
  4. 生命周期:合理使用单例和临时实例

完整示例

package main

import (
	"fmt"
	"github.com/go-kata/kinit"
)

// 配置
type Config struct {
	DBConnString string
	LogLevel     string
}

// 数据库
type Database struct {
	connString string
}

func NewDatabase(config *Config) *Database {
	return &Database{connString: config.DBConnString}
}

func (db *Database) Query() string {
	return "query result"
}

// 日志
type Logger interface {
	Log(msg string)
}

type ConsoleLogger struct {
	level string
}

func NewConsoleLogger(config *Config) Logger {
	return &ConsoleLogger{level: config.LogLevel}
}

func (l *ConsoleLogger) Log(msg string) {
	fmt.Printf("[%s] %s\n", l.level, msg)
}

// 服务
type UserService struct {
	db     *Database
	logger Logger
}

func NewUserService(db *Database, logger Logger) *UserService {
	return &UserService{db: db, logger: logger}
}

func (s *UserService) GetUser(id int) string {
	s.logger.Log(fmt.Sprintf("Fetching user %d", id))
	return s.db.Query()
}

func main() {
	// 创建容器
	ctr := kinit.NewContainer()
	
	// 注册配置(单例)
	ctr.MustProvide(func() *Config {
		return &Config{
			DBConnString: "user:pass@localhost:5432/db",
			LogLevel:     "info",
		}
	}, kinit.Singleton())
	
	// 注册数据库(单例)
	ctr.MustProvide(NewDatabase, kinit.Singleton())
	
	// 注册日志
	ctr.MustProvide(NewConsoleLogger)
	
	// 注册服务
	ctr.MustProvide(NewUserService)
	
	// 使用服务
	err := ctr.Invoke(func(service *UserService) {
		result := service.GetUser(1)
		fmt.Println("Result:", result)
	})
	
	if err != nil {
		panic(err)
	}
	
	// 输出:
	// [info] Fetching user 1
	// Result: query result
}

Kinit 提供了简洁而强大的依赖注入功能,能够帮助你构建松耦合、可测试的应用程序。通过合理使用依赖注入,你可以更容易地管理复杂的依赖关系,并提高代码的可维护性。

回到顶部