golang基于YAML的依赖注入容器插件库gontainer的使用

Golang基于YAML的依赖注入容器插件库gontainer的使用

Gontainer是一个用于Go语言的依赖注入容器,它支持并发安全、作用域和热交换功能。

安装

可以通过以下方式安装gontainer:

homebrew

brew install gontainer/homebrew-tap/gontainer

go install

go install github.com/gontainer/gontainer@latest

手动编译

git clone git@github.com:gontainer/gontainer.git
cd gontainer
GONTAINER_BINARY=/usr/local/bin/gontainer make

使用示例

YAML配置方式

创建gontainer/gontainer.yaml文件:

meta:
  pkg: "gontainer"
  constructor: "New"
  imports:
     mypkg: "github.com/user/repo/pkg"

parameters:
  appPort: '%envInt("APP_PORT", 9090)%' # 从环境变量获取端口,否则使用默认值9090

services:
  endpointHelloWorld:
    constructor: "mypkg.NewHelloWorld"

  serveMux:
    constructor: '"net/http".NewServeMux'                       # serveMux := http.NewServerMux()
    calls:                                                      #
      - [ "Handle", [ "/hello-world", "@endpointHelloWorld" ] ] # serveMux.Handle("/hello-world", gontainer.Get("endpointHelloWorld"))

  server:
    getter: "GetServer"           # func (*gontainer) GetServer() (*http.Server, error) { ... }
    must_getter: true             # func (*gontainer) MustGetServer() *http.Server { ... }
    type: '*"net/http".Server'    # 
    value: '&"net/http".Server{}' # server := &http.Server{}
    fields:                       #
      Addr: ":%appPort%"          # server.Addr = ":" + gontainer.GetParam("appPort")
      Handler: "@serveMux"        # server.Handler = gontainer.Get("serverMux")

然后编译它:

gontainer build -i gontainer/gontainer.yaml -o gontainer/container.go

Go代码方式

创建gontainer/gontainer.go文件:

package gontainer

import (
   "net/http"
   "os"

   "github.com/gontainer/gontainer-helpers/v3/container"
   "github.com/user/repo/pkg"
)

type gontainer struct {
   *container.SuperContainer
}

func (g *gontainer) MustGetServer() *http.Server {
   raw, err := g.Get("server")
   if err != nil {
      panic(err)
   }
   return raw.(*http.Server)
}

func New() *gontainer {
   sc := &gontainer{
      SuperContainer: container.NewSuperContainer(),
   }

   sc.OverrideParam("serverAddr", container.NewDependencyProvider(func() string {
      if v, ok := os.LookupEnv("APP_PORT"); ok {
         return ":" + v
      }
      return ":9090"
   }))

   endpointHelloWorld := container.NewService()
   endpointHelloWorld.SetConstructor(pkg.NewHelloWorld)
   sc.OverrideService("endpointHelloWorld", endpointHelloWorld)

   serveMux := container.NewService()
   serveMux.SetConstructor(http.NewServeMux)
   serveMux.AppendCall(
      "Handle",
      container.NewDependencyValue("/hello-world"),
      container.NewDependencyService("endpointHelloWorld"),
   )
   sc.OverrideService("serveMux", serveMux)

   server := container.NewService()
   server.SetConstructor(func() *http.Server {
      return &http.Server{}
   })
   server.SetField("Addr", container.NewDependencyProvider(func() (interface{}, error) {
      return sc.GetParam("serverAddr")
   }))
   server.SetField("Handler", container.NewDependencyService("serveMux"))
   sc.OverrideService("server", server)

   return sc
}

使用容器

创建main.go文件:

package main

import (
	"github.com/user/repo/gontainer"
)

func main() {
	c := gontainer.New()
	s := c.MustGetServer()

	err := s.ListenAndServe()
	if err != nil {
		panic(err)
	}
}

特性

  • 并发安全
  • 支持作用域
  • 支持热交换
  • 可以通过YAML或Go代码配置
  • 自动生成容器代码

Gontainer使用自举技术,使用自身来编译其依赖项,这使得它非常灵活和强大。


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

1 回复

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


Golang基于YAML的依赖注入容器插件库gontainer使用指南

gontainer是一个轻量级的Go语言依赖注入容器,支持通过YAML配置文件定义依赖关系。下面我将详细介绍如何使用gontainer。

安装

go get github.com/gontainer/gontainer

基本使用

1. 定义YAML配置文件

创建一个container.yml文件:

parameters:
  db.host: "localhost"
  db.port: 3306
  db.user: "root"
  db.pass: "password"

services:
  db.connection:
    constructor: "database/sql.Open"
    args:
      - "mysql"
      - "%db.user%:%db.pass%@tcp(%db.host%:%db.port%)/mydb"
    calls:
      - method: "SetMaxOpenConns"
        args: [10]
      - method: "SetMaxIdleConns"
        args: [5]
  
  user.repository:
    constructor: "app/repository.NewUserRepository"
    args: ["@db.connection"]
  
  user.service:
    constructor: "app/service.NewUserService"
    args: ["@user.repository"]

2. 初始化容器

package main

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

func main() {
	// 创建容器
	container := gontainer.NewContainer()
	
	// 从YAML文件加载配置
	err := container.LoadFromYAML("container.yml")
	if err != nil {
		panic(err)
	}
	
	// 获取服务
	userService, err := container.Get("user.service")
	if err != nil {
		panic(err)
	}
	
	// 使用服务
	// userService.(*service.UserService).SomeMethod()
}

高级特性

1. 参数注入

parameters:
  app.debug: true
  app.timeout: 30

services:
  logger:
    constructor: "app/logger.NewLogger"
    args: ["%app.debug%"]
  
  http.client:
    constructor: "net/http.NewClient"
    args: ["%app.timeout%"]

2. 方法调用

services:
  cache.redis:
    constructor: "github.com/go-redis/redis.NewClient"
    args:
      - addr: "localhost:6379"
    calls:
      - method: "Ping"
      - method: "Set"
        args: ["key", "value"]

3. 工厂方法

services:
  random.generator:
    factory: "math/rand.New"
    args: ["@random.source"]
  
  random.source:
    constructor: "math/rand.NewSource"
    args: [12345]

4. 标签支持

services:
  payment.processor:
    tags: ["payment", "processor"]
  
  email.sender:
    tags: ["notification"]

获取带标签的服务:

processors := container.GetByTag("payment")

实际示例

完整的Web应用示例

# container.yml
parameters:
  app.env: "dev"
  db.dsn: "user:pass@tcp(localhost:3306)/dbname?parseTime=true"

services:
  db:
    constructor: "database/sql.Open"
    args: ["mysql", "%db.dsn%"]
    calls:
      - method: "SetMaxOpenConns"
        args: [10]

  user.repository:
    constructor: "app/repositories.NewUserRepository"
    args: ["@db"]

  auth.service:
    constructor: "app/services.NewAuthService"
    args: ["@user.repository"]

  http.server:
    constructor: "app/http.NewServer"
    args: ["@auth.service", "%app.env%"]

对应的Go代码:

package main

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

func main() {
	container := gontainer.NewContainer()
	
	if err := container.LoadFromYAML("container.yml"); err != nil {
		log.Fatal(err)
	}
	
	server, err := container.Get("http.server")
	if err != nil {
		log.Fatal(err)
	}
	
	// 启动服务器
	// server.(*http.Server).Start()
}

最佳实践

  1. 分层配置:将不同环境的配置分开,如container.dev.ymlcontainer.prod.yml

  2. 模块化:将大型应用的配置拆分为多个文件

  3. 参数化:将所有可变部分提取为参数

  4. 合理使用标签:通过标签组织相关服务

  5. 错误处理:始终检查容器操作的错误

总结

gontainer提供了一种简洁的方式来管理Go应用中的依赖关系,通过YAML配置文件可以清晰地表达服务间的依赖关系。它的主要优点包括:

  • 配置与代码分离
  • 支持多种依赖注入方式
  • 轻量级且易于集成
  • 支持参数化和标签

对于中小型Go项目,gontainer是一个不错的依赖注入解决方案,能够有效降低组件间的耦合度,提高代码的可测试性和可维护性。

回到顶部