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
更多关于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应用程序的依赖管理:
- 类型安全的依赖注入
- 清晰的依赖关系声明
- 支持可选依赖和默认值
- 内置错误处理机制
- 提供缓存和条件注入等高级特性
nject特别适合构建大型应用程序,可以有效地管理复杂的依赖关系,同时保持代码的清晰和可维护性。