golang依赖注入服务容器插件库gontainer的使用

Golang依赖注入服务容器插件库Gontainer的使用

License GoDoc Test Report

Gontainer简介

Gontainer是一个用于Golang项目的依赖注入服务容器。

Gontainer

特性

  • 🚀 支持急切或延迟服务实例化,自动解析依赖关系并支持可选依赖
  • 🛠 自动注入服务工厂的依赖项,避免通过容器API手动获取
  • 🔄 自动按实例化顺序反向终止服务,确保正确释放资源和关闭
  • 📣 内置事件代理服务,用于服务容器范围内的通信和松耦合
  • 🤖 基于反射和泛型的干净、经过测试的实现,无外部依赖

示例

控制台命令示例

12:51:32 Creating new service container
12:51:32 Hello from the Hello Service Bob
12:51:32 Hello from the Hello Service Bob
12:51:32 Closing service container by defer
12:51:32 Service container closed

守护进程服务示例

12:48:22 Creating service container instance
12:48:22 Starting service container
12:48:22 Starting listening on: http://127.0.0.1:8080
12:48:22 Starting serving HTTP requests
12:48:22 Awaiting service container done
------ Application was started and now accepts HTTP requests -------------
------ CTRL+C was pressed or a TERM signal was sent to the process -------
12:48:28 Service container done chan closed
12:48:28 Closing service container by defer
12:48:28 Service container closed

完整Web应用示例

15:19:48 INFO msg="Starting service container" service=logger
15:19:48 INFO msg="Configuring app endpoints" service=app
15:19:48 INFO msg="Configuring health endpoints" service=app
15:19:48 INFO msg="Starting HTTP server" service=http address=127.0.0.1:8080
15:19:48 INFO msg="Service container started" service=logger
------ Application was started and now accepts HTTP requests -------------
15:19:54 INFO msg="Serving home page" service=app remote-addr=127.0.0.1:62640
15:20:01 INFO msg="Serving health check" service=app remote-addr=127.0.0.1:62640
------ CTRL+C was pressed or a TERM signal was sent to the process -------
15:20:04 INFO msg="Closing service container" service=logger
15:20:04 INFO msg="Closing HTTP server" service=http
15:20:04 INFO msg="Service container closed" service=logger

瞬时服务示例

11:19:22 Creating new service container
11:19:22 Starting service container
11:19:22 New value: 42
11:19:22 New value: 42
11:19:22 New value: 42
11:19:22 Closing service container by defer
11:19:22 Service container closed

服务函数示例

12:47:21 Creating new service container
12:47:21 Starting service container
12:47:21 Closing service container by defer
12:47:21 Starting service function with 42
12:47:21 Exiting from service function
12:47:21 Service container closed

快速入门

1. 定义示例服务

// MyService 执行一些关键任务
type MyService struct{}

// SayHello 输出友好的问候
func (s *MyService) SayHello(name string) {
    log.Println("Hello,", name)
}

2. 定义服务工厂

func NewMyService() *MyService {
   return new(MyService)
}

3. 在容器中注册服务工厂

container, err := gontainer.New(
   // 在容器中定义MyService工厂
   gontainer.NewFactory(NewMyService),

   // 这里我们可以定义依赖于`*MyService`的额外服务
   // 所有依赖都通过工厂函数参数声明
   gontainer.NewFactory(func(service *MyService) {
      service.SayHello("Username")
   }),
)
if err != nil {
   log.Fatalf("Failed to init service container: %s", err)
}

4. 启动容器并运行所有工厂

if err := container.Start(); err != nil {
   log.Fatalf("Failed to start service container: %s", err)
}

5. 替代方案:使用Resolver或Invoker服务

var myService *MyService
if err := container.Resolver().Resolve(&MyService); err != nil {
    log.Fatalf("Failed to resolve dependency: %s", err)
}
myService.DoSomething()

或者

if err := container.Invoker().Invoke(func(myService *MyService) {
    myService.DoSomething()
}); err != nil {
    log.Fatalf("Failed to invoke a function: %s", err)
}

关键概念

服务工厂

服务工厂是服务容器的关键组件,作为创建服务实例的机制。服务工厂本质上是一个接受其他服务作为参数并返回一个或多个服务实例的函数,可选地还可以返回一个错误。

// MyServiceFactory 是服务工厂的示例
func MyServiceFactory( /* 服务依赖 */) *MyService {
   // 初始化服务实例
   return new(MyService)
}

// MyServiceFactory 依赖于两个服务
func MyServiceFactory(svc1 MyService1, svc2 MyService2) MyService {...}

// MyServiceFactory 提供两个服务
func MyServiceFactory() (MyService1, MyService2) {...}

// MyServiceFactory 提供两个服务并返回错误
func MyServiceFactory() (MyService1, MyService2, error) {...}

// MyServiceFactory 只返回错误
func MyServiceFactory() error {...}

// MyServiceFactory 不提供任何内容
func MyServiceFactory() {...}

服务

服务是应用程序的功能组件,由服务工厂创建和管理。服务的生命周期与整个容器的生命周期相关联。

// MyService 定义示例服务
type MyService struct {}

// SayHello 是服务领域方法示例
func (s *MyService) SayHello(name string) {
    fmt.Println("Hello,", name)
}

// Close 是从容器的Close()调用的可选方法
func (s *MyService) Close() error {
   // 同步清理逻辑在这里
   return nil
}

服务函数

服务函数是从工厂返回的签名func() errorfunc()的函数。当容器启动时,此函数在后台执行,并在容器关闭时等待。

// MyServiceFactory 是服务函数使用的示例
// 这里的上下文是工厂级别的上下文。当工厂被调用时启动
// (在容器启动或服务解析时)并在工厂关闭时取消
func MyServiceFactory(ctx context.Context) func() error {
    return func() error {
        // 等待其在容器关闭时的顺序
        <-ctx.Done()
      
        // 从`service.Close()`返回nil
        return nil
    }
}

完整示例Demo

package main

import (
	"log"
	"github.com/NVIDIA/gontainer"
)

// MyService 定义示例服务
type MyService struct{}

// SayHello 输出友好的问候
func (s *MyService) SayHello(name string) {
	log.Println("Hello,", name)
}

// NewMyService 创建MyService实例
func NewMyService() *MyService {
	return new(MyService)
}

func main() {
	// 创建容器并注册服务
	container, err := gontainer.New(
		gontainer.NewFactory(NewMyService),
		gontainer.NewFactory(func(s *MyService) {
			s.SayHello("Gopher")
		}),
	)
	if err != nil {
		log.Fatalf("Failed to create container: %v", err)
	}

	// 启动容器
	if err := container.Start(); err != nil {
		log.Fatalf("Failed to start container: %v", err)
	}

	// 使用Resolver获取服务
	var myService *MyService
	if err := container.Resolver().Resolve(&myService); err != nil {
		log.Fatalf("Failed to resolve service: %v", err)
	}
	myService.SayHello("World")

	// 关闭容器
	if err := container.Close(); err != nil {
		log.Fatalf("Failed to close container: %v", err)
	}
}

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

1 回复

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


使用gontainer实现Golang依赖注入

gontainer是一个轻量级的Go语言依赖注入容器库,它提供了简单而强大的依赖注入功能。下面我将详细介绍gontainer的使用方法。

安装gontainer

首先安装gontainer库:

go get github.com/gontainer/gontainer

基本用法

1. 创建容器

package main

import (
	"fmt"
	"github.com/gontainer/gontainer"
)

type Database struct {
	DSN string
}

type Service struct {
	DB *Database `inject:""`
}

func main() {
	// 创建容器
	container := gontainer.New()

	// 注册服务
	container.Register("database", &Database{
		DSN: "user:password@tcp(localhost:3306)/dbname",
	})

	container.Register("service", &Service{})

	// 获取服务
	var service *Service
	if err := container.Get("service", &service); err != nil {
		panic(err)
	}

	fmt.Printf("Service DB DSN: %s\n", service.DB.DSN)
}

2. 构造函数注入

package main

import (
	"fmt"
	"github.com/gontainer/gontainer"
)

type Logger interface {
	Log(message string)
}

type FileLogger struct {
	filePath string
}

func (l *FileLogger) Log(message string) {
	fmt.Printf("Log to file %s: %s\n", l.filePath, message)
}

type App struct {
	logger Logger `inject:"logger"`
}

func NewApp() *App {
	return &App{}
}

func main() {
	container := gontainer.New()

	// 注册带参数的构造函数
	container.Register("logger", func(filePath string) *FileLogger {
		return &FileLogger{filePath: filePath}
	}).WithArgs("/var/log/app.log")

	container.Register("app", NewApp)

	var app *App
	if err := container.Get("app", &app); err != nil {
		panic(err)
	}

	app.logger.Log("Application started")
}

3. 接口绑定

package main

import (
	"fmt"
	"github.com/gontainer/gontainer"
)

type Mailer interface {
	Send(email string, message string) error
}

type SMTPMailer struct {
	host string
	port int
}

func (m *SMTPMailer) Send(email string, message string) error {
	fmt.Printf("Sending email to %s via %s:%d: %s\n", email, m.host, m.port, message)
	return nil
}

type NotificationService struct {
	mailer Mailer `inject:"mailer"`
}

func main() {
	container := gontainer.New()

	// 绑定接口到具体实现
	container.Register("smtp_mailer", &SMTPMailer{
		host: "smtp.example.com",
		port: 587,
	})
	
	container.Bind((*Mailer)(nil), "smtp_mailer")

	container.Register("notification", &NotificationService{})

	var service *NotificationService
	if err := container.Get("notification", &service); err != nil {
		panic(err)
	}

	service.mailer.Send("user@example.com", "Hello from gontainer!")
}

高级特性

1. 单例模式

container.Register("config", loadConfig).Singleton()

2. 标签注入

type App struct {
	Logger  Logger  `inject:"logger"`
	Version string  `inject:"version"`
}

container.Register("version", "1.0.0")

3. 方法注入

type Service struct {
	db *Database
}

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

container.Register("service", &Service{}).InjectMethods("SetDatabase")

完整示例

package main

import (
	"fmt"
	"github.com/gontainer/gontainer"
)

// 定义接口和实现
type Cache interface {
	Get(key string) (string, bool)
	Set(key, value string)
}

type MemoryCache struct {
	data map[string]string
}

func NewMemoryCache() *MemoryCache {
	return &MemoryCache{
		data: make(map[string]string),
	}
}

func (c *MemoryCache) Get(key string) (string, bool) {
	val, ok := c.data[key]
	return val, ok
}

func (c *MemoryCache) Set(key, value string) {
	c.data[key] = value
}

// 业务服务
type UserService struct {
	Cache Cache `inject:"cache"`
}

func (s *UserService) GetUser(id string) string {
	if val, ok := s.Cache.Get(id); ok {
		return val
	}
	// 模拟从数据库获取
	user := "User-" + id
	s.Cache.Set(id, user)
	return user
}

func main() {
	// 创建容器
	container := gontainer.New()

	// 注册服务
	container.Register("cache", NewMemoryCache()).Singleton()
	container.Register("userService", &UserService{})

	// 获取服务
	var userService *UserService
	if err := container.Get("userService", &userService); err != nil {
		panic(err)
	}

	// 使用服务
	fmt.Println(userService.GetUser("123")) // 第一次从数据库获取
	fmt.Println(userService.GetUser("123")) // 第二次从缓存获取
}

总结

gontainer提供了简洁而强大的依赖注入功能,主要特点包括:

  1. 支持结构体字段注入和方法注入
  2. 支持接口绑定
  3. 支持单例模式
  4. 轻量级,无额外依赖
  5. 简单易用的API

通过使用gontainer,你可以更好地组织Go应用程序的依赖关系,提高代码的可测试性和可维护性。

回到顶部