golang基于Guice的依赖注入工具包插件库dingo的使用

Golang基于Guice的依赖注入工具包插件库dingo的使用

Dingo是一个受Google Guice启发的Golang依赖注入框架,它通过绑定实现和接口之间的关系,然后在需要时由Dingo解析这些依赖。

基本使用示例

下面是一个完整的Dingo使用示例,展示如何定义服务、模块和进行依赖注入:

package main

import (
	"fmt"
	"flamingo.me/dingo"
)

// 定义接口
type CreditCardProcessor interface {
	Process(amount float64) error
}

type TransactionLog interface {
	Log(message string)
}

// 实现接口
type PaypalCreditCardProcessor struct{}

func (p *PaypalCreditCardProcessor) Process(amount float64) error {
	fmt.Printf("Processing payment of $%.2f via PayPal\n", amount)
	return nil
}

type DatabaseTransactionLog struct{}

func (d *DatabaseTransactionLog) Log(message string) {
	fmt.Println("Logging transaction:", message)
}

// 服务结构体
type BillingService struct {
	processor      CreditCardProcessor
	transactionLog TransactionLog
}

// 注入方法
func (b *BillingService) Inject(
	processor CreditCardProcessor,
	transactionLog TransactionLog,
) {
	b.processor = processor
	b.transactionLog = transactionLog
}

// 业务方法
func (b *BillingService) Charge(amount float64) error {
	err := b.processor.Process(amount)
	if err != nil {
		return err
	}
	b.transactionLog.Log(fmt.Sprintf("Charged $%.2f", amount))
	return nil
}

// 模块定义
type BillingModule struct{}

func (m *BillingModule) Configure(injector *dingo.Injector) {
	// 绑定接口到具体实现
	injector.Bind(new(CreditCardProcessor)).To(PaypalCreditCardProcessor{})
	injector.Bind(new(TransactionLog)).To(DatabaseTransactionLog{})
}

func main() {
	// 创建注入器
	injector, err := dingo.NewInjector()
	if err != nil {
		panic(err)
	}

	// 初始化模块
	injector.InitModules(new(BillingModule))

	// 获取BillingService实例
	instance, err := injector.GetInstance(new(BillingService))
	if err != nil {
		panic(err)
	}

	// 使用服务
	billingService := instance.(*BillingService)
	err = billingService.Charge(100.50)
	if err != nil {
		fmt.Println("Charge failed:", err)
	}
}

依赖注入的两种方式

Dingo支持两种方式请求依赖注入:

  1. 使用结构体标签注入公共字段:
type MyService struct {
	Processor CreditCardProcessor `inject:""`
}
  1. 实现Inject()方法注入私有字段:
type MyService struct {
	processor CreditCardProcessor
}

func (m *MyService) Inject(processor CreditCardProcessor) {
	m.processor = processor
}

提供者(Providers)的使用

Dingo允许注入提供者(工厂函数)而不是直接注入实例:

type pizzaProvider func() Pizza

type Service struct {
	provider pizzaProvider
}

func (s *Service) Inject(provider pizzaProvider) {
	s.provider = provider
}

绑定类型

Dingo提供了多种绑定方式:

  1. 基本绑定:
injector.Bind(new(Something)).To(MyType{})
  1. 使用提供者绑定:
func createSomething(thing SomethingElse) *Something {
	return &MySomething{somethingElse: thing}
}

injector.Bind(new(Something)).ToProvider(createSomething)
  1. 绑定实例:
var myInstance = new(MyType)
injector.Bind(new(Something)).ToInstance(myInstance)
  1. 多绑定(MultiBindings):
injector.BindMulti(new(Something)).To(MyType1{})
injector.BindMulti(new(Something)).To(MyType2{})

// 使用时注入切片
type Consumer struct {
	List []Something `inject:""`
}

作用域(Scopes)

Dingo支持单例作用域:

// 全局单例
injector.Bind(new(Something)).In(dingo.Singleton).To(MyType{})

// 子注入器单例
injector.Bind(new(Something)).In(dingo.ChildSingleton).To(MyType{})

// 急切加载的单例
injector.Bind(new(Something)).To(MyType{}).AsEagerSingleton()

初始化Dingo

完整的Dingo初始化流程:

func main() {
	// 创建注入器
	injector, err := dingo.NewInjector()
	if err != nil {
		panic(err)
	}

	// 初始化模块
	injector.InitModules(new(MyModule1), new(MyModule2))

	// 获取实例
	instance, err := injector.GetInstance(new(MyService))
	if err != nil {
		panic(err)
	}
	
	// 使用服务
	service := instance.(*MyService)
	service.DoSomething()
}

配置注入示例

Dingo可以注入配置值:

type ConfigService struct {
	APIKey string `inject:"config:myModule.apiKey"`
}

// 在模块中绑定配置
func (m *MyModule) Configure(injector *dingo.Injector) {
	injector.Bind("my-secret-key").AnnotatedWith("config:myModule.apiKey").ToInstance("12345")
}

拦截器(Interceptors)

Dingo支持接口拦截:

func (m *Module) Configure(injector *dingo.Injector) {
	injector.BindInterceptor(new(MyInterface), MyInterceptor{})
}

type MyInterceptor struct {
	MyInterface
}

func (i *MyInterceptor) SomeMethod() {
	// 前置处理
	i.MyInterface.SomeMethod()
	// 后置处理
}

Dingo提供了灵活的依赖注入解决方案,特别适合大型应用程序和模块化开发。它的设计灵感来自Guice,但针对Go语言的特点进行了优化。


更多关于golang基于Guice的依赖注入工具包插件库dingo的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于Guice的依赖注入工具包插件库dingo的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang依赖注入工具dingo使用指南

dingo是一个受Google Guice启发的Golang依赖注入框架,它提供了轻量级的依赖注入功能。下面我将详细介绍dingo的使用方法。

基本概念

dingo的核心概念包括:

  • Module:定义绑定的配置单元
  • Injector:负责创建和管理依赖关系的容器
  • Provider:提供实例创建逻辑的函数

安装dingo

go get github.com/hellofresh/dingo

基本使用示例

1. 定义接口和实现

package main

type Database interface {
    Connect() string
}

type MySQLDatabase struct{}

func (m *MySQLDatabase) Connect() string {
    return "Connected to MySQL"
}

2. 创建Module

package main

import "github.com/hellofresh/dingo"

type AppModule struct{}

func (m *AppModule) Configure(injector *dingo.Injector) {
    // 绑定接口到具体实现
    injector.Bind(new(Database)).To(new(MySQLDatabase))
    
    // 也可以绑定到实例
    // injector.Bind(new(Database)).ToInstance(&MySQLDatabase{})
}

3. 使用依赖注入

package main

import (
    "fmt"
    "github.com/hellofresh/dingo"
)

type App struct {
    DB Database `inject:""`
}

func main() {
    // 创建注入器并加载模块
    injector := dingo.NewInjector(new(AppModule))
    
    // 创建应用实例并注入依赖
    var app App
    if err := injector.Apply(&app); err != nil {
        panic(err)
    }
    
    fmt.Println(app.DB.Connect()) // 输出: Connected to MySQL
}

高级特性

1. 命名绑定

func (m *AppModule) Configure(injector *dingo.Injector) {
    injector.Bind(new(Database)).To(new(MySQLDatabase)).Named("mysql")
    injector.Bind(new(Database)).To(new(PostgresDatabase)).Named("postgres")
}

// 使用时
type App struct {
    MySQLDB Database `inject:"mysql"`
    PostgresDB Database `inject:"postgres"`
}

2. 提供者函数

func (m *AppModule) Configure(injector *dingo.Injector) {
    injector.Bind(new(Database)).ToProvider(func() (Database, error) {
        return &MySQLDatabase{}, nil
    })
}

3. 单例模式

func (m *AppModule) Configure(injector *dingo.Injector) {
    injector.Bind(new(Database)).To(new(MySQLDatabase)).In(dingo.Singleton)
}

4. 构造函数注入

type Service struct {
    db Database
}

func NewService(db Database) *Service {
    return &Service{db: db}
}

func (m *AppModule) Configure(injector *dingo.Injector) {
    injector.Bind(new(*Service)).ToConstructor(NewService)
}

实际应用示例

package main

import (
    "fmt"
    "github.com/hellofresh/dingo"
)

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

type DB interface {
    Query(query string) string
}

// 具体实现
type ConsoleLogger struct{}

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

type MySQLDB struct{}

func (db *MySQLDB) Query(query string) string {
    return "Result for: " + query
}

// 服务
type UserService struct {
    Logger Logger `inject:""`
    DB     DB     `inject:""`
}

func (s *UserService) GetUser(id int) {
    result := s.DB.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %d", id))
    s.Logger.Log(result)
}

// 模块
type AppModule struct{}

func (m *AppModule) Configure(injector *dingo.Injector) {
    injector.Bind(new(Logger)).To(new(ConsoleLogger))
    injector.Bind(new(DB)).To(new(MySQLDB))
    injector.Bind(new(*UserService)).ToConstructor(func(l Logger, db DB) *UserService {
        return &UserService{Logger: l, DB: db}
    })
}

func main() {
    injector := dingo.NewInjector(new(AppModule))
    
    var userService *UserService
    if err := injector.Get(&userService); err != nil {
        panic(err)
    }
    
    userService.GetUser(1)
    // 输出:
    // LOG: Result for: SELECT * FROM users WHERE id = 1
}

最佳实践

  1. 模块化设计:将相关绑定分组到不同的模块中
  2. 接口优先:尽量针对接口编程而非具体实现
  3. 避免循环依赖:设计时要考虑依赖关系
  4. 合理使用单例:对于资源密集型对象考虑使用单例

dingo是一个轻量级的依赖注入框架,适合中小型项目使用。对于更复杂的场景,你也可以考虑其他更成熟的DI框架如Wire或Dig。

回到顶部