golang类型安全的反射框架插件库nject的使用

Golang类型安全的反射框架插件库nject的使用

nject是一个提供类型安全依赖注入的Golang库,它不需要用户进行类型断言。

安装

go get github.com/muir/nject/v2

核心概念

nject通过调用链进行依赖注入:列出需要调用的函数,这些函数接收和返回各种参数。函数将按顺序调用,使用早期函数的返回值作为后期函数的参数。只有为了能够调用链中最后一个函数而需要调用的函数才会被调用。

示例

func example() {
    // 序列可以重复使用
    providerChain := Sequence("example sequence",
        // 可以注入常量
        "a literal string value",
        // 当下游需要int时会运行这个函数
        func(s string) int {
            return len(s)
        })
    Run("example",
        providerChain,
        // 列表中的最后一个函数总是会运行。这个函数需要一个int和一个string。
        // string可以来自常量,int可以来自provider chain中的函数
        func(i int, s string) {
            fmt.Println(i, len(s))
        })
}

主要API

nject提供两个主要API:Bind()和Run()。

  • Bind():当性能很重要时使用。给定一个提供者链,它会写入两个函数:一个用于初始化链,另一个用于调用它。
  • Run():当需要临时注入且性能不关键时使用。Run会立即执行链。

提供者类型

nject支持多种类型的提供者:

字面值

可以直接提供常量值。

注入器

常规函数可以提供值。注入器可以在初始化时调用(如果标记为可缓存)或在调用时调用(如果不可缓存)。

包装器(中间件)

包装器是特殊函数,负责调用注入链中位于它们之后的部分。它们通过调用nject框架为它们定义的inner()函数来实现这一点。

调试注入链

如果链成功绑定但没有按预期工作,可以在链中添加接收nject.Debugging类型的代码:

func(d *nject.Debugging) {
    fmt.Println("Injectors included\n", d.Included)
}

使用场景

nject已成功用于:

  • 测试框架
  • 端点处理程序
  • 服务器启动

开发状态

nject的核心是稳定可靠的。新功能有测试,但可能没有足够的生产使用来保证可靠性。

相关包

以下包使用nject提供更好的API:

  • nape:用于绑定http端点处理程序的依赖注入包装器
  • nchi:基于httprouter的http路由器
  • nfigure:配置和标志处理
  • npoint:用于绑定http端点处理程序的依赖注入包装器
  • nserve:用于启动和停止服务器的注入链
  • ntest:支持函数和提示,用于使用nject编写测试
  • nvalid:强制http端点符合Swagger定义
  • nvelope:用于构建端点的注入链

更多关于golang类型安全的反射框架插件库nject的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang类型安全的反射框架插件库nject的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang类型安全的反射框架nject使用指南

nject是一个Go语言的依赖注入框架,它提供了类型安全的依赖注入功能,通过反射机制实现,但保证了类型安全性。下面我将介绍nject的基本用法和示例代码。

安装nject

go get github.com/muir/nject

基本概念

nject的核心概念是"Provider"(提供者)和"Collection"(集合):

  • Provider:一个可以产生值的函数
  • Collection:一组Provider的组合

基本用法

简单示例

package main

import (
	"fmt"
	"github.com/muir/nject"
)

func main() {
	// 创建一个注入集合
	collection := nject.Sequence("example",
		// 提供字符串
		func() string {
			return "Hello, World!"
		},
		// 使用字符串
		func(s string) {
			fmt.Println(s)
		},
	)

	// 执行注入
	err := nject.Run("example", collection)
	if err != nil {
		panic(err)
	}
}

类型安全的依赖注入

package main

import (
	"fmt"
	"github.com/muir/nject"
)

type Database struct {
	connString string
}

type Service struct {
	db *Database
}

func main() {
	collection := nject.Sequence("service-example",
		// 提供数据库连接字符串
		func() string {
			return "user:password@tcp(localhost:3306)/dbname"
		},
		// 创建数据库实例
		func(connString string) *Database {
			return &Database{connString: connString}
		},
		// 创建服务
		func(db *Database) *Service {
			return &Service{db: db}
		},
		// 使用服务
		func(s *Service) {
			fmt.Printf("Service with DB: %v\n", s.db.connString)
		},
	)

	err := nject.Run("service-example", collection)
	if err != nil {
		panic(err)
	}
}

可选依赖和默认值

package main

import (
	"fmt"
	"github.com/muir/nject"
)

type Config struct {
	Host string
	Port int
}

func main() {
	collection := nject.Sequence("config-example",
		// 默认配置
		func() Config {
			return Config{
				Host: "localhost",
				Port: 8080,
			}
		},
		// 可选覆盖配置
		nject.Optional(func(cfg *Config) {
			cfg.Port = 9090
		}),
		// 使用配置
		func(cfg Config) {
			fmt.Printf("Server running on %s:%d\n", cfg.Host, cfg.Port)
		},
	)

	err := nject.Run("config-example", collection)
	if err != nil {
		panic(err)
	}
}

错误处理

package main

import (
	"errors"
	"fmt"
	"github.com/muir/nject"
)

func main() {
	collection := nject.Sequence("error-example",
		// 可能出错的提供者
		func() (string, error) {
			return "", errors.New("something went wrong")
		},
		// 使用字符串
		func(s string) {
			fmt.Println("This won't be called because of the error")
		},
	)

	err := nject.Run("error-example", collection)
	if err != nil {
		fmt.Println("Error:", err)
	}
}

中间件模式

package main

import (
	"fmt"
	"github.com/muir/nject"
	"net/http"
)

func main() {
	collection := nject.Sequence("http-middleware",
		// 提供http请求和响应
		func(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, *http.Request) {
			return w, r
		},
		// 日志中间件
		func(w http.ResponseWriter, r *http.Request, next func()) {
			fmt.Printf("Request: %s %s\n", r.Method, r.URL.Path)
			next()
		},
		// 认证中间件
		func(w http.ResponseWriter, r *http.Request, next func()) {
			if r.Header.Get("Authorization") == "" {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}
			next()
		},
		// 业务处理
		func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte("Hello, authenticated user!"))
		},
	)

	// 模拟HTTP请求
	w := &mockResponseWriter{}
	r := &http.Request{
		Method: "GET",
		Header: http.Header{
			"Authorization": []string{"Bearer token"},
		},
	}

	err := nject.Run("http-middleware", collection, w, r)
	if err != nil {
		fmt.Println("Error:", err)
	}
}

type mockResponseWriter struct{}

func (m *mockResponseWriter) Header() http.Header        { return http.Header{} }
func (m *mockResponseWriter) Write([]byte) (int, error)  { return 0, nil }
func (m *mockResponseWriter) WriteHeader(statusCode int) {}

高级特性

缓存提供者

package main

import (
	"fmt"
	"github.com/muir/nject"
	"time"
)

func main() {
	collection := nject.Sequence("cache-example",
		// 缓存这个提供者的结果
		nject.Memoize(func() time.Time {
			fmt.Println("Computing current time...")
			return time.Now()
		}),
		// 使用时间
		func(t time.Time) {
			fmt.Println("Time:", t)
		},
		// 再次使用时间 - 会使用缓存的值
		func(t time.Time) {
			fmt.Println("Same time:", t)
		},
	)

	err := nject.Run("cache-example", collection)
	if err != nil {
		panic(err)
	}
}

条件提供者

package main

import (
	"fmt"
	"github.com/muir/nject"
)

func main() {
	collection := nject.Sequence("conditional-example",
		// 根据环境决定提供什么
		func(env string) string {
			if env == "production" {
				return "production-config"
			}
			return "development-config"
		},
		// 使用配置
		func(config string) {
			fmt.Println("Using config:", config)
		},
	)

	// 模拟生产环境
	err := nject.Run("conditional-example", collection, "production")
	if err != nil {
		panic(err)
	}

	// 模拟开发环境
	err = nject.Run("conditional-example", collection, "development")
	if err != nil {
		panic(err)
	}
}

总结

nject是一个功能强大且类型安全的依赖注入框架,它通过以下特性简化了Go应用程序的依赖管理:

  1. 类型安全的依赖注入
  2. 清晰的依赖关系声明
  3. 支持可选依赖和默认值
  4. 内置错误处理机制
  5. 提供缓存和条件注入等高级特性

nject特别适合构建大型应用程序,可以有效地管理复杂的依赖关系,同时保持代码的清晰和可维护性。

回到顶部